2016-05-13 8 views
2

Ich habe eine Datei wie folgt aus:Bestücken Liste <Object> LINQ mit

City|Country|Phone Number 
Name 
City|Country|Phone Number 
Name 
City|Country|Phone Number 
Name 

und so weiter ...

Ich habe eine Klasse wie gemacht:

class Person 
{ 
string city, country, phone, name; 
} 

dieses große Nach der Lektüre Datei, möchte ich eine Liste erstellen und alle Werte in ihren jeweiligen Feldern platzieren.

Meine Arbeit so weit

List<PersonObj> objectsList = new List<PersonObj>(); 

string[] peopleFile = System.IO.File.ReadAllLines(fileName); 

var oddLines = peopleFile.Where((src, index) => index % 2 != 0); 
var evenLines = peopleFile.Where((src, index) => index % 2 == 0); 

und seine erfolgreich Abrufen Adresse und den Namen Leitungen getrennt in oddLines und evenLines sind.

What I Want

Ich sollte objectsList bevölkert eher mit LINQ als sie eins nach dem anderen bevölkern Schleife

Vielen Dank für Ihre Hilfe

+0

Was meinst du mit "in einer Linie"? –

+0

@BrianMain Oh, ich meine direkt mit LINQ. Ich habe die Frage aktualisiert –

Antwort

2

Dies tun sollten, was Sie

wollen
var people = File.ReadLines(fileName) 
    .Select((l,i) => new { Line = l.Split('|'), LineNo = i }) 
    .GroupBy(x => x.LineNo/2) 
    .Select(grp => new Person 
     { 
      city = grp.First().Line[0], 
      country = grp.First().Line.Skip(1).FirstOrDefault(), 
      phone = grp.First().Line.Skip(2).FirstOrDefault(), 
      name = grp.Last().Line[0] 
     }) 
    .ToList(); 

Grundsätzlich verwenden Sie die Überlast von Select, die geben s Sie den Index und das können Sie nach der Zeilennummer gruppieren, so dass Sie Gruppen der ersten 2 Zeilen, der nächsten 2 Zeilen und so weiter erhalten. Dann ziehe einfach von der ersten oder letzten Zeile in der Gruppe (es sollte nur 2 sein) und dem Index des Arrays von der Teilung.

Beachten Sie, dass diese falsche Ergebnisse geben wird, wenn die Datei nicht das Format entspricht, wie die name und city das gleiche gilt für die letzte Eintrag, wenn die Datei eine ungerade Anzahl von Zeilen hat oder die country oder phone ist null wenn die ungeraden Zeilen nicht mindestens zwei Pipe-Zeichen enthalten.

Außerdem habe ich File.ReadLines anstelle von File.ReadAllLines verwendet, um zu vermeiden, dass ein unnötiges Zwischenarray erstellt wird.

+0

Danke! Ich komme zurück zu Ihnen, nachdem ich es überprüft habe –

+0

Es gibt Fehler bei der Verwendung der Indizierung. Fehler liest als: Kann die Indizierung mit [] nicht auf einen Ausdruck vom Typ 'Anonymous Type # 1' anwenden. –

+0

@TalhaIrfan Mein Fehler, ich habe das jetzt behoben, indem ich auf die Eigenschaft 'Line' der anonymen Klasse, die ich erstelle, verweise. – juharr

1

Sie können dies mit Zip tun. Ich nehme an, dass evenLines die Städte etc. und oddLines die Namen enthält.

var persons = oddLines.Zip(
    evenLines.Select(line => line.Split('|')), 
    (name, data) => new Person {name = name, city = data[0], country = data[1], phone = data[2]});     

Zip verbindet jede Zeile oddLines mit der entsprechenden Zeile des evenLines. Diese zweite Zeile wird durch | geteilt und für jede Kombination wird ein neues Person Objekt erzeugt und mit seinen Daten gefüllt.

Natürlich sollte es etwas mehr Fehlerbehandlung geben, da dies Ausnahmen auslösen kann, wenn in Ihrer Datei Werte fehlen.

+0

Danke Rene. Ja, anfällig für Fehler durch unvollständige/fehlende Daten, aber wirklich schlau. Ich werde es versuchen –

1

Zur besseren Trennung von Sorge, könnten Sie zunächst die beiden Ergebnisse in oddLines kombinieren und evenLines ein komplettes string zu erstellen:

var lines = from o in oddLines 
      from ev in evenLines 
      select o + "|" + ev; 

und dann doppelt LINQSelect verwenden:

objectsList = lines.Select(x => x.Split('|')) 
    .Select(y => new PersonObj() { 
     city = y[0], 
     country = y[1], 
     phone = y[2], 
     name = y[3], 
    }).ToList(); 

der ersten Select wird verwendet, um jede Zeile in der Datei auf string[] mit 4 Elementen zu teilen und die zweite Select wird verwendet, um cr eate PersonObj Artikel von ihnen.

Beachten Sie, dass Sie Ihre Felder (city, country, phone, name) zu public anstelle von private machen müssen, um dies zu tun.

+1

Der 'Name' ist in einer anderen Zeile, so wird dies nicht funktionieren. – juharr

+0

@juharr Sie haben Recht, Antwort aktualisiert ... – Ian

+0

@Ian Danke Ian. Interessanter Ansatz: verwendet sehr einfaches LINQ. –

1

ist hier ein LINQ Weg:

class Person 
{ 
    public string Name { get; set; } 
    public string Country { get; set; } 
    public string City { get; set; } 
    public string PhoneNumber { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     string[] lines = File.ReadAllLines("data.txt"); 

     List<Person> people = 
      lines 
       .Select((line, index) => 
        new 
        { 
         Index = index/2, 
         RawData = line 
        } 
       ) 
       .GroupBy(obj => obj.Index) 
       .Select(group => 
        { 
         var rawPerson = group.ToArray(); 

         string name = rawPerson[1].RawData; 
         string[] rawDetails = rawPerson[0].RawData.Split('|'); 

         return 
          new Person() 
          { 
           Name = name, 
           City = rawDetails[0], 
           Country = rawDetails[1], 
           PhoneNumber = rawDetails[2] 
          }; 
        } 
       ) 
       .ToList(); 
    } 
} 
+0

Danke !! Ich bin so froh, so viele verschiedene Ansätze für die gleiche Sache zu sehen. Ich habe heute viel gelernt :) –