2010-09-23 8 views
5

Ich habe zwei Sequenzen (von Tupeln), auf dem ein ich tun muss JOIN:Wie rufe ich Enumerable.Join von F #?

  • Seq 1: [(City1 * Pin1), (City2 * Pin2), (City1 * Pin3), (City1 * PIN4)]
  • Seq 2: [(Pin1 * ProduktA), (Pin2 * ProduktB), (Pin1 * ProductC), (Pin2 * ProduktA)]

in die Sequenz (von Tupeln):

  • [(Stadt1 * ProduktA), (Stadt2 * StadtB), (Stadt * ProduktC), (City2 * A Produkt) ...]

In C# Ich könnte dies die Linq Methode Join Erweiterung verwenden tun:

seq1.Join(seq2, t => t.Item2, t=> t.Item1, 
    (t,u) => Tuple.Create(t.Item1, u.Item2)) 

Wie kann ich das erreichen in F #? Ich kann nicht finden, bei Seq dort beitreten.

+0

Ich bin auf der Suche nach einer effizienten Implementierung, da diese Liste von Produkten/Pin ziemlich lang ist. Linq scheint für mich gut zu funktionieren, kann aber nicht von f # zur Arbeit kommen. –

+0

Haben F # -Sequenzen sogar "IEnumerable" implementiert? Wenn nicht, können Sie LINQ nicht verwenden. –

+0

Ja, sie implementieren IEnumerable. –

Antwort

6

Edit: Eigentlich kann man nur LINQ verwenden:

> open System.Linq;; 
> let ans = seq1.Join(seq2, (fun t -> snd t), (fun t -> fst t), (fun t u -> (fst t, snd u)));; 

Warum F # 's nativen Seq Funktionen nicht? Wenn Sie at the docs und schauen, können Sie diese einfach anstelle von LINQ verwenden. Nehmen Sie die Seq.map2 Funktion zum Beispiel:

> let mapped = Seq.map2 (fun a b -> (fst a, snd b)) seq1 seq2;; 

val it : seq<string * string> = 
    seq [("city1", "product1"); ("city2", "product2")] 

sollten Sie geben, was Sie wollen, wo seq1 und seq2 Ihre ersten und zweiten Sequenzen sind.

+0

Städte wären eins zu viele mit Pin und Pins wären viele zu viele mit Produkten. Können Sie erklären, wie es funktionieren würde? –

+0

Meinst du, du hättest '[(City1 * Pin1 * Pin2), (City2 * Pin2)]' und '[(Pin1 * ProductA), (Pin2 * ProductB * Productc)]' dh mit Tupel, die mehr als 2 Elemente? –

+0

Nein, ich meine, ich könnte mehrere Elemente in der Sequenz mit derselben Stadt und einem anderen Pin haben. Ähnlich könnte ich mehrere Elemente mit demselben Pin und anderen Produkten haben oder umgekehrt in Seq 2. Das Tupel wird immer 2 Elemente haben. –

2

F # Interactive Sitzung:

> let seq1 = seq [("city1", "pin1"); ("city2", "pin2")];; 

val seq1 : seq<string * string> = [("city1", "pin1"); ("city2", "pin2")] 

> let seq2 = seq [("pin1", "product1"); ("pin2", "product2")];; 

val seq2 : seq<string * string> = [("pin1", "product1"); ("pin2", "product2")] 

> Seq.zip seq1 seq2;; 
val it : seq<(string * string) * (string * string)> = 
    seq 
    [(("city1", "pin1"), ("pin1", "product1")); 
    (("city2", "pin2"), ("pin2", "product2"))] 
> Seq.zip seq1 seq2 |> Seq.map (fun (x,y) -> (fst x, snd y));; 
val it : seq<string * string> = 
    seq [("city1", "product1"); ("city2", "product2")] 

Außerdem müssen Sie in der Lage sein, Linq Abfragen auf Sequenzen zu verwenden, nur sicher sein, Sie einen Verweis auf die System.Linq Baugruppe haben und öffnete einen Namespace open System.Linq

UPDATE: in einem komplexen Szenario Sie Sequenz Ausdrücke verwenden können wie folgt:

open System 

let seq1 = seq [("city1", "pin1"); ("city2", "pin2"); ("city1", "pin3"); ("city1", "pin4")] 
let seq2 = seq [("pin1", "product1"); ("pin2", "product2"); ("pin1", "product3"); ("pin2", "product1")] 

let joinSeq = seq { for x in seq1 do 
         for y in seq2 do 
          let city, pin = x 
          let pin1, product = y 
          if pin = pin1 then 
           yield(city, product) } 
for(x,y)in joinSeq do 
    printfn "%s: %s" x y 

Console.ReadKey() |> ignore 
+0

3 Sekunden vor mir! Sollte keine Links hinzugefügt haben ... –

+0

Städte hätten mehr als einen Pin und Pins wären viele zu viele mit Produkten. –

+0

Also, was der letzte Befehl tut: mache eine Liste von Tupelpaaren als vorherigen Befehl (Seq.zip), mappe diese Liste dann auf das neue, erste Element des ersten Tupels (fst x) und das zweite Element des zweiten Tupels (snd y). –

2

Ich denke, dass es nicht genau klar ist, welche Ergebnisse Sie erwarten, so dass die Antworten ein wenig verwirrend sind. Ihr Beispiel könnte auf zwei Arten interpretiert werden (entweder als zipping oder als bei) und sie sind dramatisch anders.

  • Zipping: Wenn Sie zwei Listen der gleichen Länge und Sie möchten Elemente ausrichten correspoding (zB erste Artikel aus der ersten Liste mit ersten Element aus der zweiten Liste; 2. Artikel aus der ersten Liste mit 2. Artikel aus der zweiten Liste usw.), dann schauen Sie sich die Antworten an, die entweder List.zip oder List.map2 verwenden.

    Dies würde jedoch bedeuten, dass die Listen nach Pins sortiert sind und die Pins eindeutig sind.In diesem Fall müssen Sie nicht Join verwenden, und selbst in C#/LINQ können Sie die Erweiterungsmethode Zip verwenden.

  • Beitritt: Wenn die Listen unterschiedliche Längen haben, können die Pins nicht sortiert oder nicht eindeutig sein, dann müssen Sie einen echten Join schreiben. Eine vereinfachte Version des Codes durch Artem K würde wie folgt aussehen:

    seq { for city, pin1 in seq1 do 
         for pin2, product in seq2 do 
          if pin1 = pin2 then yield city, product } 
    

    Diese weniger effizient sein kann als Join in LINQ, weil es in seq1 durch alle Elemente in seq2 für jedes Element Schleifen, so dass die Komplexität O(seq1.Length * seq2.Length). Ich bin mir nicht sicher, aber ich denke, dass Join etwas Hashing verwenden könnte, um effizienter zu sein. Statt Join Verfahren direkt zu verwenden, würde ich wahrscheinlich ein wenig Helfer definieren:

    open System.Linq 
    module Seq = 
        let join (seq1:seq<_>) seq2 k1 k2 = 
        seq1.Join(seq2, (fun t -> k1 t), (fun t -> k2 t), (fun t u -> t, u)) 
    

    Dann können Sie so etwas schreiben:

    (seq1, seq2) 
        ||> Seq.join snd fst 
        |> Seq.map (fun (t, u) -> fst t, snd u) 
    

Schließlich, wenn Sie wissen, dass es genau das ist einzigartige Stadt für jedes Produkt (die Sequenzen haben die gleiche Länge und Pins sind einzigartig in beiden), dann können Sie beide Sequenzen nur nach Pins sortieren und dann verwenden zip - dies kann effizienter sein als mit join (vor allem, wenn Sie behalten könnten die Reihenfolge von einigen früheren Operationen sortiert).

+0

Hallo, ich wollte ein Join (Cross-Produkt) und es implementiert mit einem Wörterbuch in LINQ, die es schneller macht. –

Verwandte Themen