Autor Beitrag
Vitalic
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 68



BeitragVerfasst: So 05.09.10 18:14 
Hallo Alle zusammen!

Ich habe ein kleines Problem beim Listen-Vergleich.

Es ist mir klar, dass man Listen anhand von Schleifen vergleichen könnte.

Beispielsweise so:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
        for (int i = 0; i < feld1.Length; i++) 
        {
            for (int j = 0; j < feld2.Length; j++) 
            {
                if (feld1[i] == feld2[j]) 
                { 
                    Console.WriteLine(feld1[i]);
                }
            }


Aber was ist, wenn ich jetzt mehrere Listen habe?
Ich habe nicht die Lust noch weitere Schleifen zu verwenden, es muss doch eine Möglichkeit geben das ganze dynamisch zu gestalten...

Gruß

Vitalic

Moderiert von user profile iconChristian S.: C#-Tags hinzugefügt
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: So 05.09.10 18:33 
Zitat:
Aber was ist, wenn ich jetzt mehrere Listen habe?


Man schreibt sich eine Methode, entsprechend deinem Code, die 2 Listen vergleicht und ruft die mehrmals auf.
Also wenn du z.B 3 Listen feld1, feld2, feld3 hast (ich finde es übrigens blöd Listen mit einem Singular zu benennen aus dem der Listencharacter nicht zwingend hervorgeht) und eine Methode z.B. Namens ListEquals dann wäre das

ausblenden C#-Quelltext
1:
2:
if ((ListEquals(feld1,feld2) && ListEquals(feld1,feld3))
   ...



Die üblichen Listentypen sollten übrigens bereits eine SequenceEqual Methode mitliefern (ab 3.5). Es gibt eigentlich keinen Grund eine eigene zu schreiben.

ausblenden C#-Quelltext
1:
2:
if (feld1.SequenceEqual(feld2) && feld1.SequenceEqual(feld3))
   ...
Vitalic Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 68



BeitragVerfasst: So 05.09.10 18:56 
Danke, das ist sicherlich bessere Möglichkeit Listen zu vergleichen, aber so richtig dynamisch ist da ja auch nicht.

In meinem Fall könnte ich sogar mehr als 10 Listen haben und ich kann nie genau sagen wie viele es sind.
Es sind in jedem Fall mehr oder gleich 3 Listen.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4798
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: So 05.09.10 19:15 
Wenn du mehrere Listen hast, so kannst du diese selber wieder in eine Liste packen, d.h.
ausblenden C#-Quelltext
1:
List<List<int>> lists = new List<List<int>>();					

und statt 'int' dann deinen benötigten Datentypen einsetzen.

Wenn du dann jede Liste mit den anderen vergleichen willst, dann einfach eine 2-fache Schleife:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
for(int i=0; i<lists.Count; i++)
  for(int j=i+1; j<lists.Count; j++)
  {
    // Vergleich der Liste an Index i mit j
    if(lists[i].SequenceEqual(lists[j]))
    {
       // ...
    }
  }
Vitalic Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 68



BeitragVerfasst: So 05.09.10 19:44 
Ich habe jetzt mal anhand deines Beispiels versucht zu programmieren,
doch habe noch irgendwo einen Fehler, da keine Werte ausgegeben werden.

In XmlDevices habe ich jetzt mehrere Listen, welche mehrere Werte beinhalten.
Wenn es einen Wert gibt, der in allen anderen auch vorhanden ist, dann soll dieser ausgegeben werden.


private List<List<XmlDevices>> xmlDevices;
private List<XmlDevices> xmlDev;

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
       for (int i = 0; i < xmlDevices.Count; i++)
            {
                for (int j = i + 1; j < xmlDevices.Count; j++)
                {
                    // Vergleich der Liste an Index i mit j
                    if (xmlDevices[i].SequenceEqual(xmlDevices[j]))
                    {
                        xmlDev = new List<XmlDevices>();
                        xmlDev = xmlDevices[i];
                        for (int k = 0; k < xmlDev.Count; k++)
                        {
                            Console.WriteLine(xmlDev[k].getWert());
                        }
                    }
                }
            }
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: So 05.09.10 20:37 
ausblenden C#-Quelltext
1:
Wenn es einen Wert gibt, der in allen anderen auch vorhanden ist, dann soll dieser ausgegeben werden.					


Könntest du noch mal genau ansagen was du vergleichen willst und was das Ergebnis dieses Vergleichs sein soll?
Ich hätte gedacht du willst den ganzen Listeninhalt vergleichen. Das macht SequenceEqual es vergleicht jeden Wert an der selben Position in beiden beteiligten Listen und wenn alle Werte gleich sind liefert SequenceEqual true. Du scheinst aber eine andere Art von Vergleich zu meinen.
Vitalic Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 68



BeitragVerfasst: So 05.09.10 22:19 
Also, ich habe eine Liste, die mehrere Listen enthält. Nun möchte ich gucken, ob irgend ein Wert aus der ersten Liste mit den Werten aus den anderen Listen übereinstimmt. Es sollen nur die Werte aus der ersten Liste mit den Werten aus n anderen Listen verglichen werden. Beinhalten alle Listen den gleichen Wert, so wird er ausgegeben. SequenceEqual macht aber was anderes, denn damit klappt das nicht. Und wie bereits oben beschrieben ist, moechte ich das ganze dynamisch, denn in meiner Liste kann es mehrere Listen geben. Hoffe, dass das jetzt etwas genauer beschrieben ist.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: So 05.09.10 22:48 
OK. Verstanden. Um geschickt gegen alle Listen in der Liste zu prüfen hilft dir die TrueForAll Methode.
Im Beispiel habe ich eine der Listen nicht mit in die Liste der Listen gepackt dann lässt sich das einfacher mit foreach anstatt einer for Schleife darstellen.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
List<int> values = new List<int>() { 125678 };
List<List<int>> listsOfValues = new List<List<int>>() {  new List<int>() { 345690 },
                                                        new List<int>() { 125690 } };

foreach (var value in values)
    if (listsOfValues.TrueForAll(list => list.Contains(value)))
        Console.WriteLine(value);

Für diesen Beitrag haben gedankt: Vitalic
Vitalic Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 68



BeitragVerfasst: Mo 06.09.10 10:48 
user profile iconRalf Jansen hat folgendes geschrieben Zum zitierten Posting springen:
OK. Verstanden. Um geschickt gegen alle Listen in der Liste zu prüfen hilft dir die TrueForAll Methode.
Im Beispiel habe ich eine der Listen nicht mit in die Liste der Listen gepackt dann lässt sich das einfacher mit foreach anstatt einer for Schleife darstellen.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
List<int> values = new List<int>() { 125678 };
List<List<int>> listsOfValues = new List<List<int>>() {  new List<int>() { 345690 },
                                                        new List<int>() { 125690 } };

foreach (var value in values)
    if (listsOfValues.TrueForAll(list => list.Contains(value)))
        Console.WriteLine(value);



Danke, das ist genau das was ich suche, jedoch bekomme ich keine Werte, wenn ich das in meine Variante überführe.


Das ist meine Variablendeklaration:

ausblenden C#-Quelltext
1:
2:
        private List<List<XmlDevices>> xmlDevices;
        private List<XmlDevices> xmlDev;



So kann ich z.B. alle Werte auslesen:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
 xmlDev = new List<XmlDevices>();

            for (int i = 0; i < xmlDevices.Count; i++)
            {
                xmlDev = xmlDevices[i];
                for (int j = 0; j < xmlDev.Count; j++)
                {
                    Console.WriteLine(xmlDev[j].getWert());
                }
                Console.WriteLine("\n");
            }


Nun versuche ich das Beispiel vom Ralf Jansen anzuwenden, bekomme aber keinen Wert zurück, obwohl alle Listen gleiche Werte beinhalten.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
            xmlDev = xmlDevices[0];
            for (int j = 0; j < xmlDev.Count; j++)
            {
                if (xmlDevices.TrueForAll(list => list.Contains(xmlDev[j])))
                {
                    Console.WriteLine(xmlDev[j].getWert());
                }
            }
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4798
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 06.09.10 10:54 
Hallo,

hat die Klasse 'XmlDevices' denn eine passende Equals-Methode? Ansonsten würden nur die Referenzen verglichen (ich nehme mal an XmlDevices ist eine Klasse und keine Struktur (Wertetyp)).
Vitalic Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 68



BeitragVerfasst: Mo 06.09.10 11:09 
user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Hallo,

hat die Klasse 'XmlDevices' denn eine passende Equals-Methode? Ansonsten würden nur die Referenzen verglichen (ich nehme mal an XmlDevices ist eine Klasse und keine Struktur (Wertetyp)).



In meiner XmlDevices-Klasse habe ich nur setter und getter für die einzelne Werte in den Listen.
Wozu benötige ich denn noch eine passende Equals-Methode?
Er prüft doch, ob die einzelnen Objekte gleich sind, und wenn das der Fall ist, dann soll er doch den Wert an dieser Stelle ausgeben:
ausblenden C#-Quelltext
1:
Console.WriteLine(xmlDev[j].getMac());					


So speichere ich die einzelnen Werte in den Listen ab:


ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
public void saveValue(){

for(int i =0; i<founds; i++){
xmlDev.Add(new XmlDevices(wert));
}
xmlDevices.Add(xmlDev);
}



Und nun der Vergleich:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
            xmlDev = new List<XmlDevices>();
            xmlDev = xmlDevices[0];

            foreach (var value in xmlDev)
                if (xmlDevices.TrueForAll(list => list.Contains(value)))
                    Console.WriteLine(value.getMac());
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 06.09.10 13:31 
Zitat:
Wozu benötige ich denn noch eine passende Equals-Methode?
Er prüft doch, ob die einzelnen Objekte gleich sind ..


Eben und der Vergleich (in list.Contains) wird über die Equals-Methode gemacht.

Wenn du 2 mal 'new XmlDevices(wert)' für den selben wert machst werden die entstehenden XmlDevices Instanzen bei einer geerbten Standardimplementierung von Equals als unterschiedlich betrachtet. Wie Th69 schon geschrieben hat werden dann nur die Referenzen verglichen und diese sind nun mal unterschiedlich.

Siehe dazu auch die Guidelines wie Equals überschrieben werden sollte, man beachte insbesondere die Empfehlung auch GetHashcode in diesem Zug zu überschreiben.
Vitalic Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 68



BeitragVerfasst: Mo 06.09.10 14:28 
Danke an alle, also ich habe das Problem mit Eurer Hilfe gelöst, auch wenn der Lösungsweg meiner Meinung nach nicht so gut ist.

ausblenden C#-Quelltext
1:
2:
3:
4:
    private List<List<XmlDevices>> xmlDevices;
        private List<XmlDevices> xmlDev;
        private List<String> val;
        private List<List<String>> listen = new List<List<String>>();


Hier werden die Werte rausgeholt und in Listen zwischengespeichert

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
       
            xmlDev = new List<XmlDevices>();
            
            for (int i = 0; i < xmlDevices.Count; i++)
            {
                val = new List<String>();
                xmlDev = xmlDevices[i];
                for (int j = 0; j < xmlDev.Count; j++)
                {
                    val.Add(xmlDev[j].getWert());
                }
                listen.Add(val);
            }

            val = listen[0];

            foreach (var value in val)
                if (listen.TrueForAll(list => list.Contains(value)))
                {
                    Console.WriteLine("Found Devices: " + value);
                }
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4798
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 06.09.10 14:54 
Das ist wirklich "von hinten durch die Brust ins Auge" -)
Kannst du die Klasse "XmlDevices" selber nicht ändern, oder warum ignoriest du unsere Antwort bzgl. Equals?

Anstatt Contains könntest du auch Exists oder Find benutzen, um nach einem Element zu suchen (und dabei dann das Vergleichskriterium angeben):
ausblenden C#-Quelltext
1:
if (xmlDevices.TrueForAll(list => list.Exists(device => device.Property == value.Property)))					

wobei Property dann das entsprechende Vergleichskriterium wäre.

Für diesen Beitrag haben gedankt: Vitalic
Vitalic Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 68



BeitragVerfasst: Mo 06.09.10 15:28 
user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Das ist wirklich "von hinten durch die Brust ins Auge" -)
Kannst du die Klasse "XmlDevices" selber nicht ändern, oder warum ignoriest du unsere Antwort bzgl. Equals?

Anstatt Contains könntest du auch Exists oder Find benutzen, um nach einem Element zu suchen (und dabei dann das Vergleichskriterium angeben):
ausblenden C#-Quelltext
1:
if (xmlDevices.TrueForAll(list => list.Exists(device => device.Property == value.Property)))					

wobei Property dann das entsprechende Vergleichskriterium wäre.


Auch ein großes Dankeschön an Th69!!!

Ich habe das zuvor mit Equals versucht, hatte aber nie einen Fehler bekommen und hatte keine Ausgabe gehabt.

Nun habe ich die Klasse "XmlDevices" verändert und es funktioniert !=
Zitat:
"von hinten durch die Brust ins Auge"
:)