2017-07-25 6 views
-2

Ich habe eine LINQ Joining Anweisung in C#, mit dem ich versuche, eine Liste von Strukturen mit zwei Listen von Zeichenketten Linq:C# LINQ zwischen mehreren Listen beitreten

public struct ll 
{ 
    public int index; 
    public string one; 
    public string two; 
} 
public List <ll> list1; //{"0,a, ", "1,," , "2,a,dog" , "3,,horse"} 

public List <string> list2; //{"a","b"} 
public List <string> list3; //{"cat","mouse","dog"} 

Die Idee ist, dass in list1 nicht alle structs enthält einen Wert, also auf Index 0 nur list1.one hat einen Wert, der "a" ist, list1.two ist leer. Auf Index 1 sind sowohl list1.one als auch list1.two leer. Auf Index 2 haben sowohl list1.one als auch list.two Werte. Auf Index 3 hat nur list.two einen Wert.

Mit unten Ich versuche, diese drei Listen

 var query = from x in list1 
        join y1 in list2 on x.one equals y1 
        join y2 in list3 on x.two equals y2 
        select x.index; 

Mit dieser Erklärung beitreten den Join wird nur geschehen, wenn list1.one ein Element in list2 Spiele und list1.two paßt ein Element in list2. Allerdings würde ich gerne sehen, dass, wenn nur list1.one gefüllt ist, aber list1.two leer ist, der Join nur ein Element in list2 mit list1.one abgleichen wird, aber mit allen Elementen in list3, so nehmen die leere Liste1.zwei nicht berücksichtigt.

EDIT:

Lassen Sie mich die Frage anders formulieren. Mein Ziel ist es, dass das Programm einen vom Benutzer eingegebenen Satz liest, Infinitive, Substantive, Artikel und Adverbien in separaten Listen speichert und versucht, die beste Antwort oder Antwort für den Benutzer basierend auf dem Beitritt aller Listen zu finden.

So sollte list1 aussehen

public struct ll 
    { 
     int index; 
     string infinitive; 
     string noun; 
     string article; 
     string adverb; 
     string answer; 

    } 
public List <ll> list1; 

mit folgenden Daten:

enter image description here

Wenn zum Beispiel der Benutzer den Satz eingibt Join-Skript sollte zwei mögliche ‚Was können Sie finden‘ zurückkehren Antworten:

"Ich kann diese Informationen finden" und "Was soll ich finden?"

Auf dem Satz: „Was finden Sie hier“

es nur zurückkehren würde:

Aber wenn der Benutzer Askes „Ich habe diese Informationen finden kann“: „Was weißt du über dieses Hobbit“ es zurückkehren würde nichts als die Kombination „wissen“ und „die“ ist nicht bekannt, wo als „was Sie über Hobbit wissen“ mit „das weiß ich über“

Hope this ist klarer Know

+0

Können Sie uns die resultierenden Daten zeigen, die Sie in den Listen in Ihrem Beispiel sehen möchten? –

+1

Hallo Bradley. Zum Beispiel: "a" (aus Liste1) würde mit {"a", "Katze", "Maus", "Hund"} übereinstimmen und "" (aus Liste1) würde mit {"a", "b" übereinstimmen, "Katze", "Maus", "Hund"}. Am Ende würde x.index alle Indizes von list1 zurückgeben, die mit list2 und list3 verknüpft sein könnten. Daher würde es Index 0, 1 und 2 zurückgeben, da alle Elemente einschließlich Leergut zugeordnet werden könnten. Es würde niemals Index 3 von list1 zurückgeben, da es in list3 kein "Pferd" finden konnte. – HB1963

+0

Also stimmt ein leerer String mit allem überein? –

Antwort

0

Es ist zurückkehren schwer zu sagen, was Sie wollen, und vor allem wie index ist definiert, aber ich vermute so etwas. Sie möchten l1 als eine Art Liste von Suchbegriffen pro Domäne eingeben, und Sie möchten l2, l3 usw. eine Art Suchdomäne sein.

JOIN ist nicht der richtige Weg, dies zu tun. Sie möchten nur eine lineare Suche durch die Eingaben für Domänenübereinstimmungen. Sie können dies schön abstrahieren, indem Sie nicht jede Domain zu einer eigenen Liste machen, sondern einfach eine Liste von Listen erstellen und diese in der richtigen Reihenfolge durchsuchen lassen.Dies ist wie folgt:

var lists = new[] 
       { 
        new[] { "a", null }, 
        new string[] { null, null }, 
        new[] { "a", "dog" }, 
        new[] { null, "horse" } 
       }; 
var domains = new[] { new[] { "a", "b" }, new[] { "cat", "mouse", "dog" } }; 

var matches = lists.Where(list => list.Where((s, i) => s == null || domains[i].Contains(s)).Count() == list.Length); 

foreach (var list in matches) 
{ 
    Console.WriteLine(string.Join(",", list)); 
} 

Ausgang:

"a",null 
null,null 
"a","dog" 

Dann sicherlich können Sie eine Funktion schreiben, die den entsprechenden index Wert für jede Liste in den matches bestimmt, ob das, was Sie letztendlich benötigen. Ich empfehle Ihnen, Ihre index neu zu definieren, um ein Bitflag anstatt der Ad-hoc-Art zu sein, die Sie beschreiben; dann können Sie tun:

static int GetIndex<T>(IEnumerable<T> list) 
{ 
    return list.Select((s, i) => s == null ? 0 : 1 << i).Sum(); 
} 

Oder wenn Sie alles Inline wollen, dann ist es einfach

var indices = lists.Where(list => list.Where((s, i) => s == null || domains[i].Contains(s)).Count() == list.Length) 
        .Select(list => list.Select((s, i) => s == null ? 0 : 1 << i).Sum()) 
        .Distinct(); 

Oder wenn Sie einen netten Helfer indiziert-All-Funktion LINQ definieren, dann vielleicht macht es die Dinge klar:

public static bool All<T>(this IEnumerable<T> seq, Func<T, int, bool> pred) 
{ 
    return seq.Select((x, i) => Tuple.Create(x, i)).All(t => pred(t.Item1, t.Item2)); 
} 

...

IEnumerable<int> indices = lists 
    .Where(list => list.All((s, i) => s == null || domains[i].Contains(s))) 
    .Select(list => list.Select((s, i) => s == null ? 0 : 1 << i).Sum()) 
    .Distinct();