2012-12-27 21 views
5

Załóżmy, że mam tablicę. Chcę usunąć wszystkie elementy w tablicy, które mają określoną wartość. Czy ktoś wie, jak to zrobić? Wartość, którą próbuję usunąć, może wystąpić więcej niż raz, a tablica nie musi być posortowana. Wolałbym filtrować tablicę w miejscu zamiast tworzyć nową tablicę. Na przykład usunięcie wartości 2 z tablicy [1, 2, 3, 2, 4] powinno dać wynik [1, 3, 4].Usuwanie wszystkich wystąpień danej wartości z tablicy w D

To najlepsze, co mogłem wymyślić:

T[] without(T)(T[] stuff, T thingToExclude) { 
    auto length = stuff.length; 
    T[] result; 
    foreach (thing; stuff) { 
     if (thing != thingToExclude) { 
      result ~= thing; 
     } 
    } 
    return result; 
} 

stuff = stuff.without(thingToExclude); 
writeln(stuff); 

Wydaje się niepotrzebnie skomplikowane i nieefektywne. Czy jest prostszy sposób? Spojrzałem na moduł std.algorithm w standardowej bibliotece, mając nadzieję, że znajdę coś pożytecznego, ale wszystko, co wyglądałoby tak, by zrobiło to, co chciałem, było problematyczne. Oto kilka przykładów rzeczy próbowałem, które nie działały:

import std.stdio, std.algorithm, std.conv; 

auto stuff = [1, 2, 3, 2, 4]; 
auto thingToExclude = 2; 

/* Works fine with a hard-coded constant but compiler throws an error when 
    given a value unknowable by the compiler: 
    variable thingToExclude cannot be read at compile time */ 
stuff = filter!("a != " ~ to!string(thingToExclude))(stuff); 
writeln(stuff); 

/* Works fine if I pass the result directly to writeln but compiler throws 
    an error if I try assigning it to a variable such as stuff: 
    cannot implicitly convert expression (filter(stuff)) of type FilterResult!(__lambda2,int[]) to int[] */ 
stuff = filter!((a) { return a != thingToExclude; })(stuff); 
writeln(stuff); 

/* Mysterious error from compiler: 
    template to(A...) if (!isRawStaticArray!(A)) cannot be sliced with [] */ 
stuff = to!int[](filter!((a) { return a != thingToExclude; })(stuff)); 
writeln(stuff); 

Więc Jak mogę usunąć wszystkie wystąpienia wartości z tablicy, nie wiedząc, gdzie indeksy są wyświetlane?

+1

Problem z twoją ostatnią próbą to pierwszeństwo operatora: 'to! Int []' tworzy instancję szablonu 'to (T)', a następnie stosuje '[]', czyli operator plastra. Jeśli chcesz, aby nawiasy były częścią typu docelowego, potrzebujesz parens: 'to! (Int []) (...)'. To nadal nie zadziała, ale jest semantycznie poprawne. – scry

Odpowiedz

9

std.algorithm.filter jest bardzo zbliżony do tego, co chcesz: twoja druga próba jest dobra.

Będziesz chciał albo przypisać ją do nowej zmiennej, albo użyć funkcji array().

auto stuffWithoutThing = filter!((a) { return a != thingToExclude; })(stuff); 
// use stuffWithoutThing 

lub

stuff = array(filter!((a) { return a != thingToExclude; })(stuff)); 

Pierwszy z nich nie tworzy nową tablicę. Po prostu zapewnia iterację rzeczy, odfiltrowaną.

Drugi przydzieli pamięć dla nowej tablicy do przechowywania zawartości. Musisz importować moduł std.array, aby działał.

+0

Wprowadziłem drobne poprawki, a teraz twój post opisuje dokładnie to, co próbowałem zrobić. Dziękuję Ci. –

3

jeśli chcesz usunąć wartości można użyć usunąć

auto stuffWithoutThing = remove!((a) { return a == thingToExclude; })(stuff); 

nie przydzieli nową tablicę, ale pracę w miejscu, trzeba pamiętać, że zakres stuff musi być zmienny

+1

Mówisz "to nie przydzieli nowej tablicy, ale działa w miejscu". Co przez to rozumiesz? Czy spowoduje to zmianę w tablicy 'stuff'? Jeśli tak, to jaki jest cel przypisania do "stuffWithoutThing"? –

+0

Tak, to spowoduje zmiany w rzeczy, punkt przypisania jest tak, że znasz nową długość tablicy rzeczy –

+1

Dlaczego muszę przypisać tylko znać długość? Dlaczego nie mogę po prostu sprawdzić długości 'stuff'? –

5

Spójrz funkcji usuń w http://dlang.org/phobos/std_algorithm.html. Istnieją dwie strategie - stabilna i niestabilna, w zależności od tego, czy pozostałe elementy mają zachować względne pozycje. Obie strategie działają i mają złożoność O (n). Wersja niestabilna wykonuje mniej zapisów.