Biorąc pod uwagę tablicę n Obiektów, powiedzmy, że jest to tablica ciągów i ma następujące wartości:
foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";
Co muszę zrobić, aby usunąć / usunąć wszystkie ciągi / obiekty równe „a” w tablicy?
Biorąc pod uwagę tablicę n Obiektów, powiedzmy, że jest to tablica ciągów i ma następujące wartości:
foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";
Co muszę zrobić, aby usunąć / usunąć wszystkie ciągi / obiekty równe „a” w tablicy?
Odpowiedzi:
[Jeśli potrzebujesz kodu gotowego do użycia, przejdź do mojego „Edit3” (po wycięciu). Reszta jest tutaj dla potomności.]
Aby zrealizować pomysł Dustmana :
List<String> list = new ArrayList<String>(Arrays.asList(array));
list.removeAll(Arrays.asList("a"));
array = list.toArray(array);
Edit: Jestem teraz używając Arrays.asList
zamiast Collections.singleton
: Singleton jest ograniczona do jednego wejścia, natomiast asList
podejście pozwala na dodawanie innych ciągów odfiltrować później: Arrays.asList("a", "b", "c")
.
Edit2: powyższe podejście zachowuje tę samą tablicę (więc tablica ma nadal tę samą długość); element po ostatnim jest ustawiony na null. Jeśli chcesz, aby nowa tablica miała dokładnie taki rozmiar, jak jest to wymagane, użyj tego:
array = list.toArray(new String[0]);
Edycja3: Jeśli często używasz tego kodu w tej samej klasie, możesz rozważyć dodanie go do swojej klasy:
private static final String[] EMPTY_STRING_ARRAY = new String[0];
Wtedy funkcja staje się:
List<String> list = new ArrayList<>();
Collections.addAll(list, array);
list.removeAll(Arrays.asList("a"));
array = list.toArray(EMPTY_STRING_ARRAY);
Spowoduje to, że przestaniesz zaśmiecać stertę bezużytecznymi pustymi tablicami łańcuchowymi, które w przeciwnym razie byłyby edytowane za new
każdym razem, gdy wywoływana jest funkcja.
cyniczna sugestia (patrz komentarze) pomoże również w zaśmiecaniu sterty i dla uczciwości powinienem o tym wspomnieć:
array = list.toArray(new String[list.size()]);
Wolę moje podejście, ponieważ może być łatwiej uzyskać błędny rozmiar (np. Wywołanie size()
niewłaściwej listy).
Alternatywa w Javie 8:
String[] filteredArray = Arrays.stream(array)
.filter(e -> !e.equals(foo)).toArray(String[]::new);
Stream.of(foo).filter(s -> ! s.equals("a")).toArray()
byłoby wystarczające.
Utwórz a List
z tablicy za pomocą Arrays.asList()
i wywołaj remove()
wszystkie odpowiednie elementy. Następnie wywołaj toArray()
„Listę”, aby ponownie utworzyć tablicę.
Niezbyt wydajne, ale jeśli odpowiednio je hermetyzujesz, zawsze możesz zrobić coś szybciej później.
Arrays.asList()
nie obsługuje remove()
. Czy więc ta odpowiedź jest całkowicie nieprawidłowa? Wygląda na to, że niektóre komentarze zostały usunięte, więc nie wiem, czy było to omawiane.
Zawsze możesz:
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);
Możesz skorzystać z biblioteki zewnętrznej:
org.apache.commons.lang.ArrayUtils.remove(java.lang.Object[] array, int index)
Jest w projekcie Apache Commons Lang http://commons.apache.org/lang/
ArrayUtils.removeElement(boolean[] array, boolean element)
jest również bardzo przydatna.
Jeśli chcesz usunąć wiele elementów z tablicy bez konwertowania jej List
ani tworzenia dodatkowej tablicy, możesz to zrobić w O (n) niezależnie od liczby elementów do usunięcia.
Oto a
tablica początkowa, int... r
to różne uporządkowane indeksy (pozycje) elementów do usunięcia:
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"
}
Małe testy:
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]
W swoim zadaniu możesz najpierw przeskanować tablicę, aby zebrać pozycje „a”, a następnie wywołać removeItems()
.
Odpowiedzi jest wiele - problem, jak widzę, polega na tym, że nie powiedziałeś DLACZEGO używasz tablicy zamiast zbioru, więc pozwól, że zasugeruję kilka powodów i które rozwiązania będą miały zastosowanie (większość rozwiązań na które udzielono już odpowiedzi w innych pytaniach, więc nie będę wchodził w zbyt wiele szczegółów):
powód: nie wiedziałeś, że pakiet kolekcji istnieje lub nie ufałeś mu
rozwiązanie: użyj kolekcji.
Jeśli planujesz dodawać / usuwać od środka, użyj LinkedList. Jeśli naprawdę martwisz się o rozmiar lub często indeksujesz bezpośrednio w środku kolekcji, użyj ArrayList. Oba powinny mieć operacje usuwania.
powód: obawiasz się rozmiaru lub chcesz mieć kontrolę nad alokacją pamięci
rozwiązanie: użyj ArrayList o określonym rozmiarze początkowym.
ArrayList to po prostu tablica, która może się rozszerzać, ale nie zawsze musi to robić. Będzie bardzo sprytnie dodawać / usuwać elementy, ale ponownie, jeśli wstawiasz / usuwasz DUŻO ze środka, użyj LinkedList.
powód: masz tablicę przychodzącą i tablicę wychodzącą - więc chcesz operować na tablicy
rozwiązanie: przekonwertuj go na ArrayList, usuń element i przekonwertuj go z powrotem
powód: myślisz, że możesz napisać lepszy kod, jeśli zrobisz to sam
rozwiązanie: nie możesz, użyj listy Array lub Linked.
powód: to jest zadanie klasowe i nie masz pozwolenia lub z jakiegoś powodu nie masz dostępu do zbioru api
założenie: nowa tablica musi mieć odpowiedni „rozmiar”
rozwiązanie: przeskanuj tablicę pod kątem pasujących elementów i policz je. Utwórz nową tablicę o odpowiednim rozmiarze (rozmiar oryginalny - liczba dopasowań). użyj System.arraycopy wielokrotnie, aby skopiować każdą grupę elementów, które chcesz zachować, do nowej tablicy. Jeśli jest to przypisanie do klasy i nie możesz użyć System.arraycopy, po prostu skopiuj je pojedynczo ręcznie w pętli, ale nigdy nie rób tego w kodzie produkcyjnym, ponieważ jest znacznie wolniejszy. (Te rozwiązania są szczegółowo opisane w innych odpowiedziach)
powód: musisz uruchomić goły metal
założenie: NIE WOLNO niepotrzebnie przydzielać miejsca ani zajmować zbyt dużo czasu
założenie: Śledzisz rozmiar używany w tablicy (długość) oddzielnie, ponieważ w przeciwnym razie musiałbyś ponownie przydzielić tablicę do usuwania / wstawiania.
Przykład tego, dlaczego warto to zrobić: pojedyncza tablica prymitywów (powiedzmy wartości int) zajmuje znaczną część pamięci RAM - na przykład 50%! ArrayList wymusiłoby to na liście wskaźników do obiektów typu Integer, które zużywałyby kilka razy więcej pamięci.
rozwiązanie: powtórz swoją tablicę i za każdym razem, gdy znajdziesz element do usunięcia (nazwijmy go elementem n), użyj System.arraycopy, aby skopiować koniec tablicy na element „usunięty” (źródło i miejsce docelowe to ta sama tablica) - to jest wystarczająco inteligentny, aby wykonać kopię we właściwym kierunku, aby pamięć się nie nadpisała:
System.arraycopy (ary, n + 1, ary, n, length-n) długość--;
Prawdopodobnie będziesz chciał być mądrzejszy, jeśli usuwasz więcej niż jeden element naraz. Przesuwałbyś tylko obszar między jednym „dopasowaniem” a następnym, a nie całym ogonem i, jak zawsze, unikałbyś dwukrotnego przesuwania fragmentu.
W tym ostatnim przypadku absolutnie musisz wykonać tę pracę samodzielnie, a użycie System.arraycopy jest naprawdę jedynym sposobem, aby to zrobić, ponieważ wybierze najlepszy możliwy sposób przeniesienia pamięci dla architektury komputera - powinno być wielokrotnie szybsze niż jakikolwiek kod, który mógłbyś napisać samodzielnie.
Coś w tworzeniu listy, a następnie usuwaniu i wracaniu do tablicy wydaje mi się złe. Nie testowałem, ale myślę, że poniższe będą działać lepiej. Tak, prawdopodobnie zbytnio optymalizuję wstępnie.
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];
}
}
Zdaję sobie sprawę, że to bardzo stary post, ale niektóre odpowiedzi mi pomogły, więc oto moja wartość za dwa pensy!
Zmagałem się z tym, aby to działało przez dłuższy czas, zanim przekręciłem, że tablica, do której piszę, musi zostać zmieniona, chyba że zmiany wprowadzone w liście ArrayList
pozostawiają niezmieniony rozmiar.
Jeśli to ArrayList
, co modyfikujesz, kończy się na większej lub mniejszej liczbie elementów niż na początku, linia List.toArray()
spowoduje wyjątek, więc potrzebujesz czegoś takiego jak List.toArray(new String[] {})
lub List.toArray(new String[0])
, aby utworzyć tablicę z nowym (prawidłowym) rozmiarem.
Teraz, kiedy już to wiem, wydaje się oczywiste. Nie jest to takie oczywiste dla nowicjusza z Androidem / Javą, który zmaga się z nowymi i nieznanymi konstrukcjami kodu i nie jest oczywiste z niektórych wcześniejszych postów tutaj, więc chciałem tylko, aby ta kwestia była naprawdę jasna dla każdego, kto drapie się po głowie godzinami, tak jak ja !
EDYTOWAĆ:
Punkt z wartościami null w tablicy został wyczyszczony. Przepraszam za moje komentarze.
Oryginalny:
Ehm ... linia
array = list.toArray(array);
zastępuje wszystkie luki w tablicy, w której usunięty element miał wartość null . Może to być niebezpieczne , ponieważ elementy są usuwane, ale długość tablicy pozostaje taka sama!
Jeśli chcesz tego uniknąć, użyj nowego parametru Array jako parametru toArray (). Jeśli nie chcesz używać removeAll, alternatywą byłby zestaw:
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));
Daje:
[a, bc, dc, a, ef]
[dc, ef, bc]
Gdzie jako obecnie zaakceptowana odpowiedź od Chrisa Yestera Younga:
[a, bc, dc, a, ef]
[bc, dc, ef, null, ef]
z kodem
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));
bez pozostawionych wartości null.
Mój mały wkład w ten problem.
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;
}
}
To zależy od tego, co masz na myśli mówiąc „usuń”? Tablica jest konstrukcją o stałym rozmiarze - nie możesz zmienić liczby zawartych w niej elementów. Możesz więc albo a) utworzyć nową, krótszą tablicę bez elementów, których nie chcesz lub b) przypisać wpisy, których nie chcesz, do czegoś, co wskazuje na ich status „pusty”; zwykle null, jeśli nie pracujesz z prymitywami.
W pierwszym przypadku utwórz Listę z tablicy, usuń elementy i utwórz nową tablicę z listy. Jeśli wydajność jest ważna, iteruj po tablicy, przypisując wszystkie elementy, które nie powinny być usuwane z listy, a następnie utwórz nową tablicę z listy. W drugim przypadku po prostu przejdź i przypisz null do wpisów tablicy.
Arrgh, nie mogę uzyskać poprawnego wyświetlenia kodu. Przepraszam, udało mi się. Przepraszam jeszcze raz, nie sądzę, żebym poprawnie przeczytał pytanie.
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++;
}
}
W tablicy ciągów, takich jak
String name = 'abcdeafbde' // może wyglądać jak String name = 'aa bb cde aa f bb de'
Buduję następującą klasę
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()
uzyskanie tego wyniku
Alfabet
Mam nadzieję, że ten kod pomoże każdemu. Pozdrawiam
Jeśli nie ma znaczenia kolejność elementów. możesz przełączać się między elementami foo [x] i foo [0], a następnie wywołać foo.drop (1).
foo.drop(n)
usuwa (n) pierwsze elementy z tablicy.
Myślę, że jest to najprostszy i efektywny pod względem zasobów sposób.
PS : indexOf
można zaimplementować na wiele sposobów, to jest moja wersja.
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);
}