如何从 Java 数组中删除对象?
给定一个 n 对象数组,假设它是一个字符串数组,并且它具有以下值:
foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";
我需要做什么才能删除/删除所有字符串/数组中的对象等于“a”?
Given an array of n Objects, let's say it is an array of strings, and it has the following values:
foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";
What do I have to do to delete/remove all the strings/objects equal to "a" in the array?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(20)
如果您需要从数组中删除多个元素,而不将其转换为
List
或创建其他数组,则可以在 O(n) 内完成,而不依赖于要删除的项目数。这里,
a
是初始数组,int...r
是要删除的元素的不同有序索引(位置):小测试:
在您的任务中,您可以首先扫描数组收集“a”的位置,然后调用
removeItems()
。If you need to remove multiple elements from array without converting it to
List
nor creating additional array, you may do it in O(n) not dependent on count of items to remove.Here,
a
is initial array,int... r
are distinct ordered indices (positions) of elements to remove:Small testing:
In your task, you can first scan array to collect positions of "a", then call
removeItems()
.这里有很多答案 - 我看到的问题是你没有说为什么你使用数组而不是集合,所以让我提出几个原因以及适用的解决方案(大多数解决方案这里已经在其他问题中得到了回答,所以我不再赘述):
原因:您不知道集合包存在或不信任它
解决方案:使用集合。
如果您打算从中间添加/删除,请使用 LinkedList。 如果您确实担心大小或经常在集合中间建立索引,请使用 ArrayList。 这两个都应该有删除操作。
原因:您担心大小或想要控制内存分配
解决方案:使用具有特定初始大小的 ArrayList。
ArrayList 只是一个可以自行扩展的数组,但并不总是需要这样做。 添加/删除项目会非常聪明,但是如果您要从中间插入/删除很多项目,请使用 LinkedList。
原因:您有一个数组传入和一个数组传出 - 所以您想对数组进行操作
解决方案:将其转换为 ArrayList,删除该项目并将其转换回来
原因:您认为如果您自己动手就可以编写更好的代码
解决方案:您不能,请使用数组或链接列表。
原因:这是一个类分配,您不被允许或者由于某种原因您无权访问集合 api
假设:您需要新数组成为正确的“大小”
解决方案:
扫描数组中的匹配项并对其进行计数。 创建一个正确大小的新数组(原始大小 - 匹配数)。 重复使用 System.arraycopy 将您希望保留的每组项目复制到新数组中。 如果这是一个类分配,并且您无法使用 System.arraycopy,只需在循环中手动复制它们,但不要在生产代码中执行此操作,因为它要慢得多。 (这些解决方案在其他答案中都有详细介绍)
原因:您需要运行裸机
假设:您不得分配不必要的空间或花费太长时间
假设:您正在跟踪数组中使用的大小(长度)分开,因为否则你必须重新分配数组以进行删除/插入。
您可能想要这样做的一个例子:单个基元数组(比方说 int 值)占用了您的 ram 的很大一部分——比如 50%! ArrayList 会强制将它们放入指向 Integer 对象的指针列表中,这将使用几倍的内存量。
解决方案:迭代数组,每当找到要删除的元素(我们称之为元素 n)时,使用 System.arraycopy 将数组的尾部复制到“已删除”元素上(源和目标是相同的数组) - 它足够聪明,可以按照正确的方向进行复制,因此内存不会覆盖自身:
如果您一次删除多个元素,您可能会希望比这更聪明。 您只需移动一个“匹配”与下一个“匹配”之间的区域,而不是整个尾部,并且一如既往地避免将任何块移动两次。
在最后一种情况下,您绝对必须自己完成这项工作,并且使用 System.arraycopy 实际上是唯一的方法,因为它将为您的计算机体系结构选择移动内存的最佳方法 - 它应该快很多倍比您自己可以合理编写的任何代码都要好。
There are a lot of answers here--the problem as I see it is that you didn't say WHY you are using an array instead of a collection, so let me suggest a couple reasons and which solutions would apply (Most of the solutions have already been answered in other questions here, so I won't go into too much detail):
reason: You didn't know the collection package existed or didn't trust it
solution: Use a collection.
If you plan on adding/deleting from the middle, use a LinkedList. If you are really worried about size or often index right into the middle of the collection use an ArrayList. Both of these should have delete operations.
reason: You are concerned about size or want control over memory allocation
solution: Use an ArrayList with a specific initial size.
An ArrayList is simply an array that can expand itself, but it doesn't always need to do so. It will be very smart about adding/removing items, but again if you are inserting/removing a LOT from the middle, use a LinkedList.
reason: You have an array coming in and an array going out--so you want to operate on an array
solution: Convert it to an ArrayList, delete the item and convert it back
reason: You think you can write better code if you do it yourself
solution: you can't, use an Array or Linked list.
reason: this is a class assignment and you are not allowed or you do not have access to the collection apis for some reason
assumption: You need the new array to be the correct "size"
solution:
Scan the array for matching items and count them. Create a new array of the correct size (original size - number of matches). use System.arraycopy repeatedly to copy each group of items you wish to retain into your new Array. If this is a class assignment and you can't use System.arraycopy, just copy them one at a time by hand in a loop but don't ever do this in production code because it's much slower. (These solutions are both detailed in other answers)
reason: you need to run bare metal
assumption: you MUST not allocate space unnecessarily or take too long
assumption: You are tracking the size used in the array (length) separately because otherwise you'd have to reallocate your array for deletes/inserts.
An example of why you might want to do this: a single array of primitives (Let's say int values) is taking a significant chunk of your ram--like 50%! An ArrayList would force these into a list of pointers to Integer objects which would use a few times that amount of memory.
solution: Iterate over your array and whenever you find an element to remove (let's call it element n), use System.arraycopy to copy the tail of the array over the "deleted" element (Source and Destination are same array)--it is smart enough to do the copy in the correct direction so the memory doesn't overwrite itself:
You'll probably want to be smarter than this if you are deleting more than one element at a time. You would only move the area between one "match" and the next rather than the entire tail and as always, avoid moving any chunk twice.
In this last case, you absolutely must do the work yourself, and using System.arraycopy is really the only way to do it since it's going to choose the best possibly way to move memory for your computer architecture--it should be many times faster than any code you could reasonably write yourself.
关于创建一个列表然后删除然后返回数组的一些事情让我觉得错误。 还没有测试过,但我认为下面的效果会更好。 是的,我可能过度地进行了预优化。
Something about the make a list of it then remove then back to an array strikes me as wrong. Haven't tested, but I think the following will perform better. Yes I'm probably unduly pre-optimizing.
我意识到这是一篇非常老的帖子,但这里的一些答案帮助了我,所以这是我的二便士半便士的价值!
在发现我正在写回的数组需要调整大小之前,我花了很长一段时间才使其正常工作,除非对 ArrayList 所做的更改使列表大小保持不变。
如果您正在修改的 ArrayList 最终的元素数量比开始时多或少,则
List.toArray()
行将导致异常,因此您需要一些东西例如List.toArray(new String[] {})
或List.toArray(new String[0])
以便创建具有新(正确)大小的数组。现在我知道了,这听起来很明显。 对于一个正在学习新的、不熟悉的代码结构的 Android/Java 新手来说,这并不是那么明显,而且从这里之前的一些帖子来看,这一点也不是很明显,所以我只是想让其他像我一样摸不着头脑的人明白这一点。 !
I realise this is a very old post, but some of the answers here helped me out, so here's my tuppence' ha'penny's worth!
I struggled getting this to work for quite a while before before twigging that the array that I'm writing back into needed to be resized, unless the changes made to the
ArrayList
leave the list size unchanged.If the
ArrayList
that you're modifying ends up with greater or fewer elements than it started with, the lineList.toArray()
will cause an exception, so you need something likeList.toArray(new String[] {})
orList.toArray(new String[0])
in order to create an array with the new (correct) size.Sounds obvious now that I know it. Not so obvious to an Android/Java newbie who's getting to grips with new and unfamiliar code constructs and not obvious from some of the earlier posts here, so just wanted to make this point really clear for anybody else scratching their heads for hours like I was!
初始数组
如果要删除索引 2 的 51,请使用以下
Initial array
if you want remove 51 that is index 2, use following
编辑:
数组中具有空值的点已被清除。 抱歉我的评论。
原文:
嗯...该行将
数组中已删除元素所在的所有间隙替换为 null。 这可能是危险,因为元素被删除,但数组的长度保持不变!
如果您想避免这种情况,请使用新数组作为 toArray() 的参数。 如果您不想使用removeAll,则可以选择Set:
给出:
Chris Yester Young 输出当前接受的答案:
代码中
不留下任何空值。
EDIT:
The point with the nulls in the array has been cleared. Sorry for my comments.
Original:
Ehm... the line
replaces all gaps in the array where the removed element has been with null. This might be dangerous, because the elements are removed, but the length of the array remains the same!
If you want to avoid this, use a new Array as parameter for toArray(). If you don`t want to use removeAll, a Set would be an alternative:
Gives:
Where as the current accepted answer from Chris Yester Young outputs:
with the code
without any null values left behind.
我对这个问题的一点贡献。
}
My little contribution to this problem.
}
这取决于你所说的“删除”是什么意思? 数组是固定大小的构造 - 您无法更改其中元素的数量。 因此,您可以 a) 创建一个新的、更短的数组,其中不包含您不需要的元素,或者 b) 将您不需要的条目分配给指示其“空”状态的内容; 如果您不使用基元,通常为 null。
在第一种情况下,从数组创建一个列表,删除元素,然后从列表创建一个新数组。 如果性能很重要,请迭代数组,将不应删除的任何元素分配到列表中,然后从列表中创建一个新数组。 在第二种情况下,只需遍历数组条目并将 null 分配给数组条目即可。
It depends on what you mean by "remove"? An array is a fixed size construct - you can't change the number of elements in it. So you can either a) create a new, shorter, array without the elements you don't want or b) assign the entries you don't want to something that indicates their 'empty' status; usually null if you are not working with primitives.
In the first case create a List from the array, remove the elements, and create a new array from the list. If performance is important iterate over the array assigning any elements that shouldn't be removed to a list, and then create a new array from the list. In the second case simply go through and assign null to the array entries.
呃,我无法正确显示代码。 抱歉,我已经成功了。 再次抱歉,我认为我没有正确阅读问题。
Arrgh, I can't get the code to show up correctly. Sorry, I got it working. Sorry again, I don't think I read the question properly.
将复制除索引 i 之外的所有元素:
Will copy all elements except the one with index i:
如果元素的顺序无关紧要。 您可以在元素 foo[x] 和 foo[0] 之间交换,然后调用 foo.drop(1)。
foo.drop(n)
从数组中删除 (n) 个第一个元素。我想这是最简单且资源有效的方法。
PS:
indexOf
可以通过多种方式实现,这是我的版本。If it doesn't matter the order of the elements. you can swap between the elements foo[x] and foo[0], then call foo.drop(1).
foo.drop(n)
removes (n) first elements from the array.I guess this is the simplest and resource efficient way to do.
PS:
indexOf
can be implemented in many ways, this is my version.删除 仅几个相同条目中的第一个
使用 lambda
可以删除
null
条目to remove only the first of several equal entries
with a lambda
can remove
null
entries字符串数组中,
在像String name = 'abcdeafbd e' // 可能像 String name = 'aa bb cde aa f bb d e' 这样的
我构建了以下类,
得到了这个结果
bcdef
希望这段代码可以帮助任何人
问候
In an array of Strings like
String name = 'a b c d e a f b d e' // could be like String name = 'aa bb c d e aa f bb d e'
I build the following class
getting this result
a b c d e f
hope this code help anyone
Regards
将 null 分配给数组位置。
Assign null to the array locations.
[如果您想要一些现成的代码,请滚动到我的“Edit3”(剪切后)。 其余的内容供后代使用。]
为了充实Dustman 的想法:
编辑:我现在使用
数组。 asList
而不是Collections.singleton
:单例仅限于一个条目,而asList
方法允许您添加其他字符串以便稍后过滤:Arrays.asList(“a”,“b”,“c”)
。Edit2:上述方法保留了相同的数组(因此数组仍然是相同的长度); 最后一个元素之后的元素设置为 null。 如果您想要一个大小完全符合要求的新数组,请使用以下代码:
Edit3:如果您在同一个类中经常使用此代码,您可能希望考虑将其添加到您的类中:
然后该函数将变为:
这将停止在堆中散布无用的空字符串数组,否则每次调用函数时这些数组都会被
new
ed。愤世嫉俗者的建议(见评论)也将有助于堆乱扔,为了公平起见,我应该提到它:
我更喜欢我的方法,因为它可能更容易得到错误的显式大小(例如,调用
size() 放在错误的列表中)。
[If you want some ready-to-use code, please scroll to my "Edit3" (after the cut). The rest is here for posterity.]
To flesh out Dustman's idea:
Edit: I'm now using
Arrays.asList
instead ofCollections.singleton
: singleton is limited to one entry, whereas theasList
approach allows you to add other strings to filter out later:Arrays.asList("a", "b", "c")
.Edit2: The above approach retains the same array (so the array is still the same length); the element after the last is set to null. If you want a new array sized exactly as required, use this instead:
Edit3: If you use this code on a frequent basis in the same class, you may wish to consider adding this to your class:
Then the function becomes:
This will then stop littering your heap with useless empty string arrays that would otherwise be
new
ed each time your function is called.cynicalman's suggestion (see comments) will also help with the heap littering, and for fairness I should mention it:
I prefer my approach, because it may be easier to get the explicit size wrong (e.g., calling
size()
on the wrong list).Java 8 中的替代方案:
An alternative in Java 8:
使用
Arrays.asList()
从数组中创建一个List
,并对所有适当的元素调用remove()
。 然后在“List”上调用toArray()
以再次将其恢复为数组。性能不是很好,但是如果你正确封装它,你以后总是可以更快地做一些事情。
Make a
List
out of the array withArrays.asList()
, and callremove()
on all the appropriate elements. Then calltoArray()
on the 'List' to make back into an array again.Not terribly performant, but if you encapsulate it properly, you can always do something quicker later on.
你总是可以这样做:
You can always do:
您可以使用外部库:
它位于项目 Apache Commons Lang http://commons.apache.org/lang/
You can use external library:
It is in project Apache Commons Lang http://commons.apache.org/lang/
请参阅下面的代码
See code below