2017-05-11 1 views
0

Lasst uns den folgenden Ausdruck in Elixir sehen:Elixir: Verwendung `: into` für Bereich Generator (Zahlen)

iex> for n <- 1..30, rem(n, 3) == 0, do: n * 10 
[30, 60, 90, 120, 150, 180, 210, 240, 270, 300] 

Ich versuchte :into optional mit ihnen zusammenzufassen, aber es ist fehlgeschlagen:

# expect to get `1650` from `[30, 60, 90, 120, 150, 180, 210, 240, 270, 300]` 
iex> for n <- 1..30, rem(n, 3) == 0, into: 0, do: n * 10 
** (Protocol.UndefinedError) protocol Collectable not implemented for 0 
    (elixir) lib/collectable.ex:1: Collectable.impl_for!/1 
    (elixir) lib/collectable.ex:46: Collectable.into/1 

Ist es möglich, :into zu verwenden, um die Ergebnisse von aufgezählten Zahlenwerten zu kombinieren?

Wenn ja, wie?

+0

Es klingt eher wie würden Sie brauchen, [ 'Enum.reduce/2'] (https://hexdocs.pm/elixir/Enum.html#reduce/2), na ja, _reduce_ Liste von ganzen Zahlen in eine ganze Zahl ... –

+0

Bedenken Sie: '1..30 |> Enum.filter (fn n -> rem (n, 3) == 0 Ende) |> Enum.reduce (0, fn n, acc -> acc + n * 10 Ende) ' –

Antwort

5

Nein, into kann nur in eine Collectable Art zu sammeln verwendet werden. Ganzzahlen sind nicht Collectable.

können Sie Enum.sum/1 hier, aber Sie wahrscheinlich schon wusste, dass:

iex(1)> Enum.sum(for n <- 1..30, rem(n, 3) == 0, do: n * 10) 
1650 

Sie Enum.reduce/3 hier allerdings verwenden können, wenn Ihr Ziel ist eine Zwischenliste nicht erstellen ist:

Enum.reduce(1..30, 0, fn n, acc -> if(rem(n, 3) == 0, do: acc + n * 10, else: acc) end) 
1650 

bearbeiten : Ganzzahlen können gemacht werden, um Collectable mit dem Verhalten zu implementieren implementieren, aber ich empfehle es nicht, weil (1) diese Implementierung wird global und (2) gibt es keine offensichtliche Möglichkeit, in eine ganze Zahl "sammeln", könnten Sie nur so wir lch verwende Multiplikation statt Addition. obwohl nur zu Lernzwecken, ist hier, wie Sie Collectable für ganze Zahlen mit Additionsverhalten implementieren würden:

defimpl Collectable, for: Integer do 
    def into(acc) do 
    {acc, fn 
     acc, {:cont, x} -> acc + x 
     acc, _ -> acc 
    end} 
    end 
end 

IO.inspect for n <- 1..30, rem(n, 3) == 0, into: 0, do: n * 10 

Ausgang:

1650 
+0

Gut, danke. Ist es möglich, dass Integer "Collectable" unterstützt? –

+1

Es wäre, aber es gibt mehr als eine Implementierung, die Sinn macht - es könnte eine Summe, ein Produkt oder ein Durchschnitt sein - nur um zu beginnen. – michalmuskala

+0

@Dogbert, super! Kann ich ein anderes Schlüsselwort anstelle von ': into' verwenden? Zum Beispiel '' sum': 'für n <- 1..30, rem (n, 3) == 0, Summe: 0, do: n * 10' –

1

Wie Dogbert ganze Zahlen schrieb nicht sammelbare Protokolle implementieren. Wenn Sie eine Aufgabe haben: "Liste in Zahl umwandeln", denken Sie an Enum.reduce.

a = for n <- 1..30, rem(n, 3) == 0, do: n * 10 
Enum.reduce a, 0, &Kernel.+/2 
> 1650