Dodaj element do tablicy, jeśli jeszcze go tam nie ma


92

Mam klasę Ruby

class MyClass
  attr_writer :item1, :item2
end

my_array = get_array_of_my_class() #my_array is an array of MyClass
unique_array_of_item1 = []

Chcę pchnąć MyClass#item1do unique_array_of_item1, ale tylko jeśli unique_array_of_item1nie zawierają że item1jeszcze. Znam proste rozwiązanie: po prostu iteruj my_arrayi sprawdź, czy unique_array_of_item1już zawiera bieżący, item1czy nie.

Czy jest jakieś wydajniejsze rozwiązanie?

Odpowiedzi:


82

Możesz użyć Set zamiast Array.


Chociaż prawdą jest, że dokumentacja mówi, że zestawy nie są uporządkowane, w rzeczywistości są (od Ruby 1.9) uporządkowane. Jeśli spojrzysz na kod, główne metody, których użyjesz do uzyskania kolejności (takie jak Set#eachi Set#to_a) delegowane @hash. A od Ruby 1.9 Hashe są zamawiane. „Hashe wyliczają ich wartości w kolejności, w jakiej zostały wstawione odpowiednie klucze”. ruby-doc.org/core-1.9.1/Hash.html
phylae

Nigdy nie było czegoś takiego jak zestaw. Są niesamowici, dziękuję bardzo
Brad

123

@Coorasse ma dobrą odpowiedź , chociaż powinna to być:

my_array | [item]

I zaktualizować my_arrayna miejscu:

my_array |= [item]

63
lub my_array |= [item]który zostanie zaktualizowany my_arrayna miejscu
andorov

2
Może czegoś tu brakuje, ale operator | = wydaje mi się nie działać? Używam Ruby 2.1.1
Viet,

@Viet |=działa dobrze w moich testach z 2.1.1. Opisz swój przypadek testowy lub otwórz nowe pytanie.
zniknie

Testuję to ponownie i teraz działa. Nie wiem, co robiłem wcześniej, odkąd mój komentarz pojawił się wiele miesięcy temu.
Viet,

1
Jaka jest złożoność tego?
Nobita,

41

Nie musisz wykonywać iteracji my_arrayręcznie.

my_array.push(item1) unless my_array.include?(item1)

Edytować:

Jak zauważa Tombart w swoim komentarzu, używanie Array#include?nie jest zbyt wydajne. Powiedziałbym, że wpływ na wydajność jest pomijalny w przypadku małych tablic, ale możesz chcieć wybrać Setwiększe.


6
zdecydowanie nie chcesz tego robić! array.include?(item)ma złożoność O(n)- więc przypomina iterację całej tablicy. spójrz na ten test porównawczy: gist.github.com/deric/4953652
Tombart,

32

Możesz przekonwertować item1 na tablicę i dołączyć do nich:

my_array | [item1]

1
To powinno być |nie ||(patrz odpowiedź Jasona)
Seth

1
Moja wina. Przepraszam. Zredagowano odpowiedź
coorasse

3

Należy pamiętać, że klasa Set i | Metoda (zwana także „Set Union”) zwróci szereg unikalnych elementów, co jest świetne, jeśli nie chcesz mieć duplikatów, ale będzie nieprzyjemną niespodzianką, jeśli masz nieunikalne elementy w swojej oryginalnej tablicy zgodnie z projektem.

Jeśli masz co najmniej jeden zduplikowany element w oryginalnej tablicy, którego nie chcesz stracić, iterowanie po tablicy z wczesnym zwrotem jest najgorszym przypadkiem O (n), co nie jest takie złe w ogólnym schemacie .

class Array
  def add_if_unique element
    return self if include? element
    push element
  end
end

0

Nie jestem pewien, czy to idealne rozwiązanie, ale zadziałało:

    host_group = Array.new if not host_group.kind_of?(Array)
    host_group.push(host)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.