2014-11-08 22 views
5

Jaki jest najlepszy sposób dodania Option s do List.Jak dodać opcje do listy

Oto moja pierwsza próba:

def append[A](as: List[A], maybeA1 : Option[A], maybeA2: Option[A]) : List[A] = as ++ maybeA1.toList ++ maybeA2.toList 

Con: stwarza 2 tmp List

(wiem .toList() jest opcjonalny, ponieważ istnieje niejawna konwersja z opcją [A], aby iterowalny [A])

Kolejna próba jest

def append2[A](ls: List[A], maybeA : Option[A]) : List[A] = maybeA.map(_ :: ls).getOrElse(ls) 
def append[A](as: List[A], maybeA1 : Option[A], maybeA2: Option[A]) : List[A] = append2(append2(as, maybeA1), maybeA2) 

Lepiej za f ale mniej czytelny ...

Czy istnieje inny sposób?

+1

Dlaczego chcesz dodać opcję [A] do listy [A]. Na pewno chcesz zobaczyć, czy jest coś wartego dodania? –

+1

Nie dodawaj do końca listy. – ziggystar

+2

Tak, nie znoszę być tym facetem w Stack Overflow, ale jeśli znajdziesz się przy końcu, warto zapytać: czy istnieje powód, dla którego używasz 'List' tutaj (zamiast jakiegoś innego rodzaju sekwencji)? –

Odpowiedz

5
def combine[A](s: Seq[A], o: Option[A]) = (s /: o)(_ :+ _) 
def combineAll[A](s: Seq[A], os: Option[A]*) = (s /: os)(combine) 

combineAll(List(1), Some(2), None, Some(3)) 
//res0: Seq[Int] = List(1, 2, 3) 
+2

Lub, dla zwięzłości: '(s /: os) ((l, o) => o.fold (l) (l: + _))' –

+0

@BenReich dzięki, włożyłem w to pomysł. Może wyglądać jak magia –

1

Można użyć zmienny List Builder

val builder = scala.collection.mutable.ListBuffer.empty[A] 
builder ++= list 
builder ++= maybe1 
builder ++= maybe2 
... 
builder.result() 

Może to dać wzrost wydajności, jeśli masz wiele opcji do dodawania, bliżej do tysięcy, myślę, że na mniejszą liczbę oryginalne rozwiązanie powinno być dobre

-2
  1. Nie można dodać Option[A] do List[A]. Musisz albo użyć List[Option[A]], a następnie dodanie opcji jest dość banalne, lub dla każdej opcji musisz sprawdzić, czy rzeczywiście coś posiada (Some(a: A)) i dodać ją tylko do listy.
  2. Jeśli kolejność elementów na liście nie jest bardzo ważna, przynajmniej nie w fazie dodawania, to najlepiej byłoby dodać je na początku, zamiast na końcu, za pomocą operatora ::. Dodawanie elementów do początku listy zajmuje stały czas. Dodanie ich na końcu zajmuje O (n) gdzie n jest liczbą elementów już na liście. Dzieje się tak dlatego, że program musi najpierw przejść całą listę od początku do końca, a dopiero potem może dodać nowy element.

Więc odpowiedź na pytanie będzie albo:

def add[A](ls: List[Option[A]], maybeA : Option[A]) = maybeA :: ls 

lub

def add[A](ls: List[A], maybeA : Option[A]) = maybeA match { 
    case Some(a) => a :: ls 
    case None => ls 
} 

A potem, po dodaniu wszystkich elementów chcesz, możesz po prostu zadzwonić ls.reverse je mieć w kolejności, w jakiej miałbyś je dołączać.

+0

Tak, możesz dodać "Opcja [A]" do "Lista [A]". Po prostu odpal REPL i wklej ten kod: 'List (1,2,3) ++ Brak ++ Some (4) ++ Some (5) ++ None' Działa to dokładnie tak samo jak twoje drugie rozwiązanie, ale jest o wiele ładniejszy. Wywołanie 'ls.reverse' spowoduje także odwrócenie oryginalnej listy, która nie jest przeznaczona. –

+0

Dzięki za naprawienie tego błędu za pomocą 'case None => ls'. Ale. 1. Autor nie powiedział nic o kontekście. Dlatego najpierw napisałem "jeśli kolejność nie jest ważna", bo może nie jest i możemy użyć '::', które jest szybsze. Poza tym dodanie opcji do listy z '++' ... cóż, to naprawdę nie dodaje ** opcji **. Dodaje ** A ** lub nic :) – makingthematrix

+0

1. Lista 'według' jest uporządkowana, więc dostarczenie rozwiązania, które zakłóca kolejność, jest w mojej książce niepoprawne. 2. Pytanie zawierało dwa przykłady tego, co autor miał na myśli "dodając opcję do listy", a gdybyś je wypróbował, zobaczyłbyś, że rzeczywiście są "dodaj A lub nic". –

Powiązane problemy