Для массива из n объектов, допустим, это массив строк со следующими значениями:
foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";
Что мне нужно сделать, чтобы удалить / удалить все строки / объекты, равные «a» в массиве?
Для массива из n объектов, допустим, это массив строк со следующими значениями:
foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";
Что мне нужно сделать, чтобы удалить / удалить все строки / объекты, равные «a» в массиве?
Ответы:
[Если вам нужен готовый код, прокрутите до моего «Edit3» (после вырезания). Остальное здесь для потомков.]
Чтобы конкретизировать идею Дастмана :
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: Приведенный выше подход сохраняет тот же массив (поэтому массив все еще имеет ту же длину); элемент после последнего устанавливается равным нулю. Если вы хотите, чтобы размер нового массива был точно таким, как требуется, используйте вместо этого:
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]
В вашей задаче вы можете сначала сканировать массив, чтобы собрать позиции «а», а затем позвонить removeItems()
.
Здесь есть много ответов - проблема, как я вижу, в том, что вы не сказали, ПОЧЕМУ вы используете массив вместо коллекции, поэтому позвольте мне предложить пару причин и какие решения будут применяться (большинство решений здесь уже были даны ответы на другие вопросы, поэтому я не буду вдаваться в подробности):
причина: вы не знали о существовании пакета сбора или не доверяли ему
Решение: используйте коллекцию.
Если вы планируете добавлять / удалять из середины, используйте LinkedList. Если вас действительно беспокоит размер или вы часто индексируете прямо в середине коллекции, используйте ArrayList. Оба они должны иметь операции удаления.
причина: вы обеспокоены размером или хотите контролировать распределение памяти
Решение: используйте ArrayList с определенным начальным размером.
ArrayList - это просто массив, который может расширяться, но это не всегда нужно делать. Будет очень разумно добавлять / удалять элементы, но, опять же, если вы вставляете / удаляете ЛОТ из середины, используйте LinkedList.
причина: у вас есть массив, входящий и выходящий массив, поэтому вы хотите работать с массивом
Решение: преобразовать его в ArrayList, удалить элемент и преобразовать обратно
причина: вы думаете, что можете написать лучший код, если сделаете это сами
Решение: вы не можете использовать массив или связанный список.
причина: это назначение класса, и вам не разрешено или у вас нет доступа к API коллекции по какой-то причине
предположение: вам нужно, чтобы новый массив был правильного «размера»
Решение: просканируйте массив на предмет совпадающих элементов и посчитайте их. Создайте новый массив правильного размера (исходный размер - количество совпадений). используйте System.arraycopy несколько раз, чтобы скопировать каждую группу элементов, которые вы хотите сохранить, в новый массив. Если это назначение класса и вы не можете использовать System.arraycopy, просто копируйте их по одному вручную в цикле, но никогда не делайте этого в производственном коде, потому что это намного медленнее. (Эти решения подробно описаны в других ответах)
причина: вам нужно запускать голый металл
предположение: вы НЕ ДОЛЖНЫ выделять пространство без необходимости или занимать слишком много времени
предположение: вы отслеживаете размер, используемый в массиве (длину) отдельно, потому что в противном случае вам пришлось бы перераспределять массив для удаления / вставки.
Пример того, почему вы можете захотеть это сделать: один массив примитивов (скажем, значения int) занимает значительную часть вашего барана - например, 50%! ArrayList включит их в список указателей на объекты Integer, которые будут использовать в несколько раз больше памяти.
Решение: выполните итерацию по вашему массиву и всякий раз, когда вы найдете элемент, который нужно удалить (назовем его элементом n), используйте System.arraycopy, чтобы скопировать хвост массива поверх «удаленного» элемента (Источник и Назначение - это один и тот же массив) - это достаточно умен, чтобы делать копию в правильном направлении, чтобы память не перезаписывалась:
System.arraycopy (арный, п + 1, арный, п, длина-п) длина -;
Вы, вероятно, захотите быть умнее этого, если удаляете более одного элемента за раз. Вы должны перемещать только область между одним «совпадением» и другим, а не весь хвост, и, как всегда, избегайте перемещения любого фрагмента дважды.
В этом последнем случае вы обязательно должны выполнить работу самостоятельно, и использование System.arraycopy - действительно единственный способ сделать это, поскольку он будет выбирать лучший способ перемещения памяти для вашей компьютерной архитектуры - это должно быть во много раз быстрее. чем любой код, который вы могли бы написать самостоятельно.
Что-то в том, чтобы составить список, затем удалить, а затем вернуться в массив, кажется мне неправильным. Не тестировал, но я думаю, что следующие будут работать лучше. Да, я, наверное, излишне заранее оптимизирую.
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, который разбирается в новых и незнакомых конструкциях кода, и не очевидно из некоторых из предыдущих публикаций здесь, поэтому просто хотел прояснить этот момент для всех, кто часами ломает голову, как я !
РЕДАКТИРОВАТЬ:
Точка с нулями в массиве очищена. Извините за мои комментарии.
Оригинал:
Эм ... линия
array = list.toArray(array);
заменяет все пробелы в массиве, где был удаленный элемент, на null . Это может быть опасно , потому что элементы удаляются, но длина массива остается прежней!
Если вы хотите избежать этого, используйте новый массив в качестве параметра для 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]
Где, как текущий принятый ответ от Криса Йестера Янга, выводится:
[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;
}
}
Это зависит от того, что вы подразумеваете под «удалением»? Массив - это конструкция фиксированного размера - вы не можете изменить количество элементов в нем. Таким образом, вы можете либо а) создать новый, более короткий массив без элементов, которые вам не нужны, или б) назначить записи, которые вы не хотите, чему-то, что указывает на их «пустой» статус; обычно null, если вы не работаете с примитивами.
В первом случае создайте список из массива, удалите элементы и создайте новый массив из списка. Если производительность важна, перебирайте массив, назначая любые элементы, которые не следует удалять, в список, а затем создайте новый массив из списка. Во втором случае просто пройдите и присвойте пустым записям массива.
Arrgh, я не могу заставить код отображаться правильно. Извините, у меня все заработало. Еще раз извините, я не думаю, что правильно прочитал вопрос.
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++;
}
}
В массиве строк типа
String name = 'abcdeafbde' // может быть как String name = '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);
}