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.asListzamiast Collections.singleton: Singleton jest ograniczona do jednego wejścia, natomiast asListpodejś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 newkaż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 Listz 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 Listani tworzenia dodatkowej tablicy, możesz to zrobić w O (n) niezależnie od liczby elementów do usunięcia.
Oto atablica początkowa, int... rto 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 ArrayListpozostawiają 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 : indexOfmoż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);
}