给定一个n个对象的数组,假设它是一个string数组,它具有以下值:
foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";
如何删除/删除数组中所有等于“ a”的字符串/对象?
Answers:
[如果需要一些现成的代码,请滚动到我的“ Edit3”(剪切后)。其余的供后代使用。]
为了充实Dustman的想法:
List<String> list = new ArrayList<String>(Arrays.asList(array));
list.removeAll(Arrays.asList("a"));
array = list.toArray(array);
编辑:我现在使用Arrays.asList
而不是Collections.singleton
:单例仅限于一个条目,而该asList
方法允许您添加其他字符串以供以后过滤:Arrays.asList("a", "b", "c")
。
Edit2:以上方法保留了相同的数组(因此数组的长度仍然相同);最后一个元素之后的元素设置为null。如果您希望新阵列的大小完全符合要求,请改用以下方法:
array = list.toArray(new String[0]);
Edit3:如果您经常在同一堂课中使用此代码,则不妨考虑将其添加到您的课中:
private static final String[] EMPTY_STRING_ARRAY = new String[0];
然后该函数变为:
List<String> list = new ArrayList<>();
Collections.addAll(list, array);
list.removeAll(Arrays.asList("a"));
array = list.toArray(EMPTY_STRING_ARRAY);
然后,这将停止用无用的空字符串数组乱堆您的堆,否则将在new
每次调用函数时对其进行编辑。
愤世嫉俗的人的建议(请参阅评论)也将有助于解决乱扔垃圾的问题,为公平起见,我应该提一下:
array = list.toArray(new String[list.size()]);
我更喜欢我的方法,因为更容易弄错显式大小(例如,调用size()
错误的列表)。
Java 8中的替代方法:
String[] filteredArray = Arrays.stream(array)
.filter(e -> !e.equals(foo)).toArray(String[]::new);
Stream.of(foo).filter(s -> ! s.equals("a")).toArray()
就足够了。
使用List
进行数组的Arrays.asList()
调用,并调用remove()
所有适当的元素。然后调用toArray()
“列表”以再次返回数组。
性能不是很出色,但是如果正确封装它,以后总是可以更快地执行。
Arrays.asList()
不支持remove()
。那么这个答案完全无效吗?看来有些评论已被删除,所以我不知道是否在讨论这个问题。
您可以随时这样做:
int i, j;
for (i = j = 0; j < foo.length; ++j)
if (!"a".equals(foo[j])) foo[i++] = foo[j];
foo = Arrays.copyOf(foo, i);
您可以使用外部库:
org.apache.commons.lang.ArrayUtils.remove(java.lang.Object[] array, int index)
它在项目Apache Commons Lang中http://commons.apache.org/lang/
ArrayUtils.removeElement(boolean[] array, boolean element)
也非常有用。
如果需要从数组中删除多个元素而不将其转换为List
或创建其他数组,则可以在O(n)中执行此操作,而不依赖于要删除的项目数。
这里a
是初始数组,int... r
是要删除的元素的不同有序索引(位置):
public int removeItems(Object[] a, int... r) {
int shift = 0;
for (int i = 0; i < a.length; i++) {
if (shift < r.length && i == r[shift]) // i-th item needs to be removed
shift++; // increment `shift`
else
a[i - shift] = a[i]; // move i-th item `shift` positions left
}
for (int i = a.length - shift; i < a.length; i++)
a[i] = null; // replace remaining items by nulls
return a.length - shift; // return new "length"
}
小测试:
String[] a = {"0", "1", "2", "3", "4"};
removeItems(a, 0, 3, 4); // remove 0-th, 3-rd and 4-th items
System.out.println(Arrays.asList(a)); // [1, 2, null, null, null]
在您的任务中,您可以首先扫描数组以收集位置“ a”,然后调用removeItems()
。
关于将其制成列表然后删除然后返回到数组的事情使我感到错误。尚未测试,但我认为以下方法会更好。是的,我可能未适当地进行预优化。
boolean [] deleteItem = new boolean[arr.length];
int size=0;
for(int i=0;i<arr.length;i==){
if(arr[i].equals("a")){
deleteItem[i]=true;
}
else{
deleteItem[i]=false;
size++;
}
}
String[] newArr=new String[size];
int index=0;
for(int i=0;i<arr.length;i++){
if(!deleteItem[i]){
newArr[index++]=arr[i];
}
}
我意识到这是一个非常古老的帖子,但是这里的一些答案帮助了我,所以这就是我的惊喜'哈彭妮的价值!
在努力重新调整要写入的数组的大小之前,我很难使它工作好一会儿,除非ArrayList
对列表大小保持不变,否则必须重新调整大小。
如果ArrayList
您要修改的最终比开始时包含更多或更少的元素,则该行将List.toArray()
导致异常,因此您需要类似List.toArray(new String[] {})
或List.toArray(new String[0])
以便创建具有新(正确)大小的数组。
我知道这听起来很明显。对于正在使用新的和不熟悉的代码构造的Android / Java新手来说,不是很明显,在这里的一些早期文章中也不是很明显,所以只想让其他人像我一样费时费力地阐明这一点!
这里有很多答案-我看到的问题是你没有说为什么要使用数组而不是集合,所以让我提出一些原因以及哪些解决方案适用(大多数解决方案在这里已经在其他问题中得到了解答,因此我不会赘述):
原因:您不知道收集程序包是否存在或不信任它
解决方案:使用集合。
如果您打算从中间添加/删除,请使用LinkedList。如果您真的担心大小或经常索引到集合的中间,请使用ArrayList。这两个都应具有删除操作。
原因:您担心大小或想要控制内存分配
解决方案:使用具有特定初始大小的ArrayList。
ArrayList只是可以自我扩展的数组,但并不总是需要这样做。添加/删除项目非常聪明,但是如果要从中间插入/删除LOT,请再次使用LinkedList。
原因:您有一个数组进来,一个数组出去了-因此您想对数组进行操作
解决方案:将其转换为ArrayList,删除该项并将其转换回
原因:您认为自己编写可以编写更好的代码
解决方案:不能使用数组或链接列表。
原因:这是一个类分配,由于某种原因,您不允许使用或无法访问集合api
假设:您需要新数组为正确的“大小”
解决方案:扫描数组以查找匹配项并计数。创建一个具有正确大小(原始大小-匹配数)的新数组。重复使用System.arraycopy将希望保留的每组项目复制到新Array中。如果这是一个类分配,并且您不能使用System.arraycopy,则只需一次循环手动将它们复制一次,但不要在生产代码中这样做,因为它要慢得多。(这些解决方案在其他答案中都有详细说明)
原因:您需要运行裸机
假设:您不得不必要地分配空间或花费太长时间
假设:您正在分别跟踪数组中使用的大小(长度),因为否则,您将不得不为删除/插入重新分配数组。
一个为什么您可能想要这样做的例子:一个原始数组(假设是int值)占用了您的ram的很大一部分,例如50%!ArrayList将强制这些指针进入指向Integer对象的指针列表,该指针将使用该数量的内存。
解决方案:遍历数组,每当找到要删除的元素时(将其称为元素n),请使用System.arraycopy将数组的尾部复制到“已删除”的元素上(源和目标是同一数组)-足够聪明,可以按正确的方向进行复制,因此内存不会覆盖自身:
System.arraycopy(ary,n + 1,ary,n,长度-n) 长度 - ;
如果一次要删除多个元素,您可能会想比这更聪明。您只会在一个“匹配”和下一个“匹配”之间移动区域,而不是整个尾巴,并且一如既往,避免将任何块移动两次。
在这最后一种情况下,您绝对必须自己完成工作,而使用System.arraycopy实际上是唯一的方法,因为它将为您的计算机体系结构选择移动内存的最佳方法-它的速度应该快很多倍比您可以合理编写自己的任何代码。
编辑:
数组中带有空值的点已被清除。对不起,我的评论。
原版的:
嗯...线
array = list.toArray(array);
用null替换数组中所有已删除元素的间隙。这可能很危险,因为删除了元素,但是数组的长度保持不变!
如果要避免这种情况,请使用新的Array作为toArray()的参数。如果您不想使用removeAll,则可以选择Set:
String[] array = new String[] { "a", "bc" ,"dc" ,"a", "ef" };
System.out.println(Arrays.toString(array));
Set<String> asSet = new HashSet<String>(Arrays.asList(array));
asSet.remove("a");
array = asSet.toArray(new String[] {});
System.out.println(Arrays.toString(array));
给出:
[a, bc, dc, a, ef]
[dc, ef, bc]
克里斯·耶斯特·杨(Chris Yester Young)当前接受的答案如下:
[a, bc, dc, a, ef]
[bc, dc, ef, null, ef]
与代码
String[] array = new String[] { "a", "bc" ,"dc" ,"a", "ef" };
System.out.println(Arrays.toString(array));
List<String> list = new ArrayList<String>(Arrays.asList(array));
list.removeAll(Arrays.asList("a"));
array = list.toArray(array);
System.out.println(Arrays.toString(array));
没有留下任何空值。
我对这个问题的贡献不大。
public class DeleteElementFromArray {
public static String foo[] = {"a","cc","a","dd"};
public static String search = "a";
public static void main(String[] args) {
long stop = 0;
long time = 0;
long start = 0;
System.out.println("Searched value in Array is: "+search);
System.out.println("foo length before is: "+foo.length);
for(int i=0;i<foo.length;i++){ System.out.println("foo["+i+"] = "+foo[i]);}
System.out.println("==============================================================");
start = System.nanoTime();
foo = removeElementfromArray(search, foo);
stop = System.nanoTime();
time = stop - start;
System.out.println("Equal search took in nano seconds = "+time);
System.out.println("==========================================================");
for(int i=0;i<foo.length;i++){ System.out.println("foo["+i+"] = "+foo[i]);}
}
public static String[] removeElementfromArray( String toSearchfor, String arr[] ){
int i = 0;
int t = 0;
String tmp1[] = new String[arr.length];
for(;i<arr.length;i++){
if(arr[i] == toSearchfor){
i++;
}
tmp1[t] = arr[i];
t++;
}
String tmp2[] = new String[arr.length-t];
System.arraycopy(tmp1, 0, tmp2, 0, tmp2.length);
arr = tmp2; tmp1 = null; tmp2 = null;
return arr;
}
}
抱歉,我无法正确显示代码。抱歉,我知道了。再次抱歉,我认为我没有正确阅读问题。
String foo[] = {"a","cc","a","dd"},
remove = "a";
boolean gaps[] = new boolean[foo.length];
int newlength = 0;
for (int c = 0; c<foo.length; c++)
{
if (foo[c].equals(remove))
{
gaps[c] = true;
newlength++;
}
else
gaps[c] = false;
System.out.println(foo[c]);
}
String newString[] = new String[newlength];
System.out.println("");
for (int c1=0, c2=0; c1<foo.length; c1++)
{
if (!gaps[c1])
{
newString[c2] = foo[c1];
System.out.println(newString[c2]);
c2++;
}
}
在像这样的字符串数组中
字符串名称='abcdeafbde'//可能像字符串名称='aa bb cde aa f bb de'
我建立以下课程
class clearname{
def parts
def tv
public def str = ''
String name
clearname(String name){
this.name = name
this.parts = this.name.split(" ")
this.tv = this.parts.size()
}
public String cleared(){
int i
int k
int j=0
for(i=0;i<tv;i++){
for(k=0;k<tv;k++){
if(this.parts[k] == this.parts[i] && k!=i){
this.parts[k] = '';
j++
}
}
}
def str = ''
for(i=0;i<tv;i++){
if(this.parts[i]!='')
this.str += this.parts[i].trim()+' '
}
return this.str
}}
return new clearname(name).cleared()
得到这个结果
abcdef
希望这段代码对任何人有帮助
如果没关系,元素的顺序。您可以在元素foo [x]和foo [0]之间交换,然后调用foo.drop(1)。
foo.drop(n)
从数组中删除(n)个第一元素。
我想这是最简单且最节省资源的方法。
PS:indexOf
可以通过多种方式实现,这是我的版本。
Integer indexOf(String[] arr, String value){
for(Integer i = 0 ; i < arr.length; i++ )
if(arr[i] == value)
return i; // return the index of the element
return -1 // otherwise -1
}
while (true) {
Integer i;
i = indexOf(foo,"a")
if (i == -1) break;
foo[i] = foo[0]; // preserve foo[0]
foo.drop(1);
}