Враховуючи масив з 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" у масиві?
Відповіді:
[Якщо вам потрібен готовий до використання код, прокрутіть до мого "Редагувати3" (після вирізу). Решта тут для нащадків.]
Щоб конкретизувати ідею Дастмена :
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]
У своєму завданні ви можете спочатку відсканувати масив, щоб зібрати позиції "а", а потім зателефонувати removeItems()
.
Тут є багато відповідей - проблема, як я бачу, полягає в тому, що ви не сказали ЧОМУ ви використовуєте масив замість колекції, тож дозвольте запропонувати кілька причин і які рішення застосовуватимуться (Більшість рішень вже отримали відповіді в інших запитаннях тут, тому я не буду вдаватися в занадто багато деталей):
причина: Ви не знали, що пакет колекцій існує, або йому не довіряли
рішення: Використовуйте колекцію.
Якщо ви плануєте додавати / видаляти з середини, використовуйте LinkedList. Якщо ви дійсно стурбовані розміром або часто індексуєте в середині колекції, використовуйте ArrayList. Обидва вони повинні мати операції видалення.
причина: Ви стурбовані розміром або хочете контролювати розподіл пам'яті
рішення: Використовуйте ArrayList із певним початковим розміром.
ArrayList - це просто масив, який може розширюватись сам, але не завжди це потрібно робити. Це буде дуже розумно щодо додавання / видалення елементів, але знову ж таки, якщо ви вставляєте / видаляєте ЛОТ із середини, використовуйте LinkedList.
причина: у вас є масив, який надходить, а масив виходить - тож ви хочете оперувати масивом
рішення: Перетворіть його в ArrayList, видаліть елемент і перетворіть назад
причина: Ви вважаєте, що можете написати кращий код, якщо зробите це самостійно
рішення: ви не можете, скористайтеся списком Array або Linked.
причина: це завдання класу, і ви з певних причин не маєте доступу або не маєте доступу до колекції apis
припущення: Вам потрібен новий масив, щоб мати правильний "розмір"
рішення: відскануйте масив на відповідні елементи та підрахуйте їх. Створіть новий масив правильного розміру (оригінальний розмір - кількість збігів). використовуйте System.arraycopy неодноразово, щоб скопіювати кожну групу елементів, які ви хочете зберегти, у свій новий масив. Якщо це призначення класу, і ви не можете використовувати System.arraycopy, просто скопіюйте їх по черзі вручну, але ніколи не робіть цього у виробничому коді, оскільки це набагато повільніше. (Ці рішення детально описані в інших відповідях)
причина: потрібно бігти оголеним металом
припущення: ви НЕ ПОВИННІ виділяти простір без потреби або займати занадто багато часу
припущення: Ви відстежуєте розмір, що використовується в масиві (довжина), окремо, оскільки в іншому випадку вам довелося б перерозподілити свій масив для видалення / вставки.
Приклад того, чому ви можете зробити це: один масив примітивів (скажімо, значення int) бере значну частину вашого оперативного пам'яті - приблизно 50%! ArrayList змусить їх увійти до списку покажчиків на об’єкти Integer, які використовуватимуть у кілька разів більше пам’яті.
рішення: Ітерація над вашим масивом, і кожного разу, коли ви знайдете елемент для видалення (назвемо його елементом n), використовуйте System.arraycopy, щоб скопіювати хвіст масиву над елементом "видалено" (джерело та призначення - це однаковий масив) достатньо розумний, щоб зробити копію у правильному напрямку, щоб пам'ять не перезаписувала себе:
System.arraycopy (ary, n + 1, ary, n, length-n) довжина--;
Напевно, ви захочете бути розумнішим, ніж це, якщо одночасно видаляєте більше одного елемента. Ви б переміщали лише область між одним "сірником" і наступним, а не цілим хвостом, і, як завжди, уникайте переміщення будь-якого шматка двічі.
В цьому останньому випадку ви абсолютно повинні виконати роботу самостійно, і використання 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;
}
}
Це залежить від того, що ви маєте на увазі під словом "видалити"? Масив - це конструкція фіксованого розміру - ви не можете змінити кількість елементів у ньому. Таким чином, ви можете: а) створити новий, коротший масив без елементів, які ви не хочете, або б) призначити записи, які ви не хочете, до чогось, що вказує на їхній статус "порожнього"; зазвичай нуль, якщо ви не працюєте з примітивами.
У першому випадку створіть Список із масиву, видаліть елементи та створіть новий масив зі списку. Якщо продуктивність важлива, переглядайте масив, призначаючи елементи, які не слід видаляти до списку, а потім створюйте новий масив зі списку. У другому випадку просто пройдіть і призначте нуль для записів масиву.
Аррх, я не можу змусити код правильно відображатися. Вибачте, я працюю. Ще раз вибачте, я не думаю, що прочитав питання належним чином.
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);
}