Ich habe Daten in Liste gespeichert, die Liste der Objekte ist.

Ich muss jede innere Liste durchlaufen und prüfen, ob das Objekt die Bedingung erfüllt, und es dann in einer anderen Liste speichern.

public class Data //class that actually holds data
{
    public string DataPart;
    public string Category;
    public Data (string dataPart, string category)
    {
        this.DataPart = dataPart;
        this.Category = category;
    }
}

Die Datenstruktur, in der Daten gespeichert werden, ist wie folgt:

Dictionary<int, List<Data>>

Beispielcode mit meiner aktuellen Lösung:

Dictionary<int, List<Data>> dataTbl = new Dictionary<int, List<Data>>();

//initializing the data structure
List<Data> lst1 = new List<Data>();
lst1.Add(new Data("data1OfLst1", "cat1"));
lst1.Add(new Data("data2OfLst1", "cat2"));
lst1.Add(new Data("data3Oflst1", "cat3"));
dataTbl.Add(1, lst1);
List<Data> lst2 = new List<Data>();
lst2.Add(new Data("data1OfLst2", "cat1"));
lst2.Add(new Data("data2OfLst2", "cat2"));
lst2.Add(new Data("data3Oflst2", "cat3"));
dataTbl.Add(2, lst2);

List<Data> cat1Data = new List<Data>();
foreach(List<Data> datList in dataTbl.Values)
{
    if(datList.Any( x => x.Category == "cat1"))
        cat1Data.Add(datList.Where(x => x.Category == "cat1").FirstOrDefault());
}

Die Anzahl der Datensätze im Wörterbuch und die Anzahl der Elemente in List jedes Datensatzes sind jedoch sehr hoch. Daher suche ich nach einer besseren Lösung.

Beachten Sie, dass es möglich ist, dass einige Datensätze in Dictionary keine solchen Daten enthalten, die die Bedingung erfüllen (hier "cat1" überprüfen). Die endgültige Liste sollte keine null Werte enthalten

BEARBEITEN:

Es wird allgemein angenommen (keine eingefleischte Validierung), dass es nur einen (oder keinen) Eintrag einer bestimmten Kategorie in der inneren Liste geben sollte, sodass es keine inneren Listen gibt, die mehr als ein Objekt mit "cat1" enthalten.

2
Amit 19 Apr. 2018 im 09:31

5 Antworten

Beste Antwort

Wie ich bereits im Kommentar erwähnt habe, sollten Sie sich nicht um schnelleren Code kümmern, solange Sie keinen Profiler verwenden, um anzugeben, ob Sie überhaupt ein Leistungsproblem haben, und wenn Also, wenn dies durch Ihren Code oder einen anderen Code verursacht wird, an den Sie nicht denken. Sie sehen: Es gibt viele Wenns.

Abgesehen davon habe ich einen intelligenteren Code für Sie, der nicht viel schneller sein wird - wenn überhaupt, aber einfacher zu lesen und damit zu pflegen, was Ihr primäres Ziel sein sollte, ist alles andere gerecht Jagd für Nano-Sekunden.

List<Data> cat1Data = new List<Data>();
foreach(List<Data> datList in dataTbl.Values)
{
    var el = datList.FirstOrDefault(x => x.Category == "cat1");
    if(el != null)
        cat1Data.Add(el);
}

FirstOrDefault gibt den Standardwert zurück (null für Referenztypen, für Strukturtypen den Standardwert der Struktur). Tatsächlich überprüfen Sie das Gleiche zweimal.

Sie müssen also nicht prüfen, ob in der aktuellen Liste ein Element vorhanden ist, das Ihrer Bedingung entspricht. Wählen Sie dieses Element anschließend erneut aus. Suchen Sie stattdessen direkt danach und fügen Sie es hinzu, wenn es gefunden wird.

3
HimBromBeere 19 Apr. 2018 im 07:23

Ich würde empfehlen, Dictionary nur zu verwenden, wenn Ihre Indizes neben der Positionsplatzierung eine besondere Bedeutung haben. In Ihrem Fall können Sie eine Liste von Listenobjekten erstellen.

 public class MainClass
{
    public int Id { get; set; }
    public List<Data> Data { get; set; }
}

Und ersetzen Sie dann Ihren Code durch

        MainClass dataTbl = new MainClass();
        List<Data> lst1 = new List<Data>();
        lst1.Add(new Data("data1OfLst1", "cat1"));
        lst1.Add(new Data("data2OfLst1", "cat2"));
        lst1.Add(new Data("data3Oflst1", "cat3"));
        dataTbl.Id = 1;
        dataTbl.Data = lst1;

        List<Data> lst2 = new List<Data>();
        lst2.Add(new Data("data1OfLst2", "cat1"));
        lst2.Add(new Data("data2OfLst2", "cat2"));
        lst2.Add(new Data("data3Oflst2", "cat3"));
        dataTbl.Id = 2;
        dataTbl.Data = lst2;

        List<Data> cat1Data = new List<Data>();

        cat1Data = dataTbl.Data.Where(i => i.Category.Contains("cat1")).ToList();

Enthält stellt sicher, dass Sie Daten mit der Kategorie "cat1" haben und keine Nullwerte enthalten.

Versuchen Sie, mich zu informieren, wenn Sie auf Probleme stoßen.

2
Sweta Nair 19 Apr. 2018 im 06:57

Sie können die Sammlungen abfragen, ohne sie zuerst zu reduzieren, und dann alle durch FirstOrDefault am Ende verursachten Nullen entfernen:

dataTbl.Values
       .Select(x => x.FirstOrDefault(y => y.Category == "cat1"))
       .Where(x=>x != null);
1
benPearce 19 Apr. 2018 im 07:00

Sie können dies tun und alle Datensätze mit cat1 abrufen

var list = dictionary.Values              // To get just the List<Data>s
                     .SelectMany(x => x)  // Flatten
                     .Where(x => x.Category == "cat1")
                     .ToList();           // Listify

Oder

var list = dictionary.SelectMany(x => x.Value)  // Flatten
                     .Where(x => x.Category == "cat1")
                     .ToList();           // Listify

Probieren Sie für die Leistung parallele Linq aus, verwenden Sie mehrere Threads, schlagen Sie jedoch vor, diese ohne parallele Leistung zu vergleichen und zu verwenden

var list = dictionary.Values.AsParallel() // To get just the List<Data>s
                     .SelectMany(x => x)  // Flatten
                     .Where(x => x.Category == "cat1")
                     .ToList();           // Listify

Hinweis: Verwenden Sie For Loop. Wenn Sie sich wirklich für die Leistung interessieren, entfernen Sie den gesamten Linq-Code, den Sie besser ausprobiert haben. Verwenden Sie nur Forloop

1
Pranay Rana 19 Apr. 2018 im 09:44

Warum überprüfen Sie den Zustand zweimal in einer Schleife? Das ist so, als würde man dreimal dasselbe machen. Wählen Sie einfach direkt zu Ihrer Liste basierend auf der Bedingung. Keine Notwendigkeit für eine Schleife und keine Notwendigkeit für die erste Überprüfung:

List<Data> cat1Data = dataTbl.Values
                             .SelectMany(x => x)
                             .Where(x => x.Category == "cat1")
                             .ToList();

Wie HenkHolterman erwähnte, kann es auch so geschrieben werden:

List<Data> cat1Data = dataTbl.SelectMany(x => x.Value)
                             .Where(x => x.Category == "cat1")
                             .ToList();

Die Ergebnisse sind identisch, aber die Leistung kann etwas variieren.

0
Racil Hilan 19 Apr. 2018 im 09:33