Hallo, ich hoffe das ist hier richtig.
Folgendes Problem. Ich habe zwei Zahlenlisten im Format:
54030;720;34;64929;930;12;30000;120;3;...
Das heißt die Information über ein Objekt hat immer 3 Zahlen zb: "54030;720;34"
Also sind immer alle dritten Einträge miteinander vergleichbar.
Mein Programm soll nun diese beiden Listen abgleichen, also für jede 3. Zahl (also erstmal die fünfstelligen) aus der einen Liste alle 3. Zahlen aus der anderen Liste anschauen und feststellen ob sie übereinstimmen. Ist das der Fall, wird die zweite (also der Eintrag im Feld dahinter) überprüft und danach der dritte Eintrag. Stimmen alle Zahlen überein, gilt das Objekt als gefunden. Alle Objekte, die nicht gefunden wurden, sollen in einer Liste mit dem Format:
54030;720;34
64929;930;12
30000;120;3
...
ausgegeben werden.
Leider funktioniert mein Algorithmus dafür noch nicht. Könnt ihr ihn euch mal anschauen und mir Verbesserungsvorschläge geben?
Hinweis: Soll[] ist das Feld mit mehr Objekten. Es sind quasi die, die hätten gefunden werden sollen
Ist[] sind die Objekte, die tatsächlich gefunden wurden. Die Felder haben auch die entsprechenden Einträge. Nur der Abgleich liefert keine fehlenden Objekte, was auf jeden Fall nicht sein kann.
//Vergleich!
i=0;
int j=1;
StreamWriter fl = new StreamWriter("../../../../final.txt");
int[] Merker = new int[Zahlenfeld2.Length];
while(i<Merker.Length)
{
Merker[i]=0;
i++;
}
i=1;
while(i<Zahlenfeld2.Length)
{
while(j<Zahlenfeld1.Length)
{
if((i+2)%3==0 && (j+2)%3==0)
{
if (Soll[i]==Ist[j])
{
if(Soll[i+1]==Ist[j+1])
{
if(Soll[i+2]==Ist[j+2])
{
Merker[i]=i;
}
}
}
}
j++;
}
i++;
}
i=1;
Console.WriteLine("Fehlende Spektren: ");
while(i<Merker.Length)
{
if((i+2)%3==0)
{
if(Merker[i] != 0)
{
Console.WriteLine(Soll[i]+";"+Soll[i+1]+";"+Soll[i+2]);
fl.WriteLine(Soll[i]+";"+Soll[i+1]+";"+Soll[i+2]);
}
}
i++;
}
fl.Flush();
fl.Close();
Console.ReadLine();
Hi,
wenn niemals Leerzeichen zwischen den Elementen einer Menge auftrten kannst du doch einfach die Strings vergleichen oder? Mit Linq's Except wäre das dann vllt 2-3 Zeilen Code.
Ich habs mal vom Code-Review ins passendere Forum verschoben. Bitte beachte unsere Regeln für das Review-Forum.
Was genau funktioniert denn nicht? Wenn du dir Objekte machen würdest, nach OOP-Ansatz, mit beispielsweise den Properties Digit1, 2 und 3, dann kannst du viel besser vergleichen, evtl. sogar einen Comparer schreiben dafür. Dann noch mit LINQ und es sollte nicht allzu schwierig werden 😉
Wenn du den LINQ-Ansatz nicht verfolgen willst sind kleine gut benannte Methoden bei solchen Aufgabestellungen meist sehr hilfreich.
Bitte beachte auch hier
[Artikel] Debugger: Wie verwende ich den von Visual Studio?
Microsoft MVP // Me // Blog // GitHub // @Egghead // All my talks // Speakerdeck
Wie meinst du das? Die Reihenfolge der Objekte in den beiden Listen stimmt ja nicht überein. Also es muss schon erstmal alle 5-stelligen Zahlen verglichen werden, so wie ich das sehe und dann weiter machen. Sicher könnte ich auch direkt die Strings verglichen, das stimmt. Aber das ist ja nicht das entscheidende Problem oder?
Was genau funktioniert denn nicht? Wenn du dir Objekte machen würdest, nach OOP-Ansatz, mit beispielsweise den Properties Digit1, 2 und 3, dann kannst du viel besser vergleichen, evtl. sogar einen Comparer schreiben dafür. Dann noch mit LINQ und es sollte nicht allzu schwierig werden 😉.
Danke! Ehrlich gesagt, hab ich keine Ahnung was LINQ und dieser OOP-Ansatz ist.
Eigentlich bin ich ja auch der Meinung, dass das was ich hab funktionieren müsste. Ich dachte, jemand der mehr Erfahrung hat, kann mir da vielleicht sagen, woran es hapert.
Was nicht funktioniert: Eigentlich müssten in meinem Beispiel 2 Objekte ausgegeben werden, die nicht gefunden wurden. Allerdings werden gar keine angezeigt. Bis zu der Codestelle, die ihr seht, funktioniert das Programm einwandfrei, also hier muss irgendwo ein Fehler liegen.
Problem gelöst! Hatte in der i-schleife vergessen "j=1;" hinzuschreiben. Somit wurde die j-Schleife ja nur einmal durchlaufen und nichts gefunden.
Danke trotzdem.
Bitte beachte [Hinweis] Wie poste ich richtig? Punkt 2.3
Kannst du noch mal schöner beschreiben, was du Vergleichen willst?
So in der Form etwa:
123; 456; 789; 123; 456; 789;
123; 456; 789; 123; 456; 789;
Dein Merker finde ich ungünstig. Stattdessen würde ich eine List verwenden. z.B.:
List<string> nichtGefundenListe = new List<string>();
//Such-Schleife
..
bool nichtGefunden = ...
...
if (nichtGefunden)
{
nichtGefundenListe.Add("123; 456; 789; 123; 456; 789");//<-- string durch gefundenes Element ersetzen
}
...
//Ausgabe
foreach(string eintrag in nichtGefundenListe)
{
Console.WriteLine(eintrag);
}
Statt Deiner while-Schleifen würde ich doch eher for(i..-Schleifen oder foreach-Schleifen verwenden.
Na dann mach doch
* Schreib eine Struct mit drei int-Properties
* zerhacke die Kette mit String.Split und ordne immer drei nachfolgende Werte diesen Structs zu (vllt ein .ctor der drei Strings aufnimmt, int's daraus parst und sie den Properties zuweist)
* du solltest dann zwei Listen mit diesen Werten haben
* dann mit Linq's Except arbeiten
//deine zwei ursprünglichen Arays heissen bei mir stringinput1, stringinput2
const string FILEPATH = @"pathToFile";
var input1 = stringinput1.Split(';').Select(p => Convert.ToInt32(p));
var input2 = stringinput2.Split(';').Select(p => Convert.ToInt32(p));
var list1 = input1.Where((p,index) => index %3 == 1).Select((p,index) => new { FirstValue = p, SecondValue = input1[3*index+1], ThirdValue = input1[3*index+2] });
var list2 = input1.Where((p, index) => index % 3 == 1).Select((p, index) => new { FirstValue = p, SecondValue = input1[3 * index + 1], ThirdValue = input2[3 * index + 2] });
var result = list1.Where(p => !list2.Any(q => q.FirstValue != p.FirstValue && q.SecondValue != p.SecondValue && q.ThirdValue != p.ThirdValue));
var sb = new StringBuilder();
result.ToList().ForEach(p => sb.AppendFormat("{0};{1};{2}\r\n", p.FirstValue, p.SecondValue, p.ThirdValue));
File.WriteAllText(FILEPATH, sb.ToString());
Geht sicher noch eleganter.
LaTino
"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)
Ich habe mal rein interesse halber drei völlig unterschiedliche Ansätze erstellt:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Coords
{
public class Program
{
public static void Main(string[] args)
{
const string coordsString1 = "54030;720;34;64929;930;12;30000;120;3;20000;20;2;10000;10;1;";
const string coordsString2 = "54030;720;34;64929;930;10;30000;120;3;20000;20;1;10000;10;1;";
var unequalCoordinates1 = ObjectVariante(coordsString1, coordsString2);
Console.WriteLine(String.Join(Environment.NewLine, unequalCoordinates1));
var unequalCoordinates2 = StringVariante(coordsString1, coordsString2);
Console.WriteLine(String.Join(Environment.NewLine, unequalCoordinates2));
var unequalCoordinates3 = RegexVariante(coordsString1, coordsString2);
Console.WriteLine(String.Join(Environment.NewLine, unequalCoordinates3));
Console.ReadLine();
}
public class Coordinate
{
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
public bool Equals(Coordinate coordinate)
{
return this.X == coordinate.X && this.Y == coordinate.Y && this.Z == coordinate.Z;
}
public override string ToString()
{
return String.Format("{0};{1};{2}", this.X, this.Y, this.Z);
}
}
private static IEnumerable<string> ObjectVariante(string coordsString1, string coordsString2)
{
var coordinates1 = ParseCoordsString(coordsString1);
var coordinates2 = ParseCoordsString(coordsString2);
var unequalCoordinates = coordinates1.Where((t, i) => !t.Equals(coordinates2[i]));
return unequalCoordinates.Select(c => c.ToString());
}
private static IList<Coordinate> ParseCoordsString(string coordsString)
{
var coordinates = new List<Coordinate>();
var coordsList1 = coordsString.TrimEnd(';').Split(';').Select(c => Convert.ToInt32(c)).ToList();
for (int i = 0; i < coordsList1.Count; i+=3)
{
var block = coordsList1.Skip(i).Take(3).ToList();
var coordinate = new Coordinate() {X = block[0], Y = block[1], Z = block[2]};
coordinates.Add(coordinate);
}
return coordinates;
}
private static IEnumerable<string> StringVariante(string coordsString1, string coordsString2)
{
var result = new List<string>();
var e1 = coordsString1.Split(';').GetEnumerator();
var e2 = coordsString2.Split(';').GetEnumerator();
while (e1.MoveNext() && e2.MoveNext())
{
string block1 = e1.Current + ";";
string block2 = e2.Current + ";";
if (e1.MoveNext() && e2.MoveNext())
{
block1 += e1.Current + ";";
block2 += e2.Current + ";";
}
else
{
return result;
}
if (e1.MoveNext() && e2.MoveNext())
{
block1 += e1.Current;
block2 += e2.Current;
}
else
{
return result;
}
if (block1 != block2)
{
result.Add(block1);
}
}
return result;
}
private static IEnumerable<string> RegexVariante(string coordsString1, string coordsString2)
{
var list1 = GetCoordBlocks(coordsString1);
var list2 = GetCoordBlocks(coordsString2);
return list1.Except(list2);
}
private static IList<string> GetCoordBlocks(string coordsString1)
{
var result = new List<string>();
var match = Regex.Match(coordsString1, "(?<block>[0-9]+;[0-9]+;[0-9]+);");
while (match.Success)
{
result.Add(match.Groups["block"].Value);
match = match.NextMatch();
}
return result;
}
}
}
Hallo Santana,
in zwei geschachtelten Schleifen alle Objekte mit allen vergleichen bedeutet quadratischen Aufwand. Zu den negativen Auswirkungen von quadratischem Aufwand bei größeren oder wachsenden Listen siehe Warum haben WinForms, DataGridView & LINQ eine gute Performance? [==> lineare Aufwandsklasse] ff und Mergesort langsamer als Bubblesort? [==> Nein, Messfehler / Aufwandsklasse vs. Mikrooptimierungen].
Man sollte entweder Dictionary/HashSet/Hashtable verwenden, um den Aufwand auf linear zu drücken (siehe [Artikel] Dictionary/HashSet/Hashtable: Grundlegende Informationen, Abschnitt "Hashtables zur schnellen Prüfung auf Enthaltensein") oder eine Linq-Variante verwenden, die intern die genannten Datenstrukturen verwendet.
Tut man das nicht bekommt man - möglicherweise plötzliche - Performance-Probleme, wenn die Liste im Laufe der Zeit wächst oder man es irgendwann zufällig mal mit einer viel größeren Liste zu tun hat.
BTW: Um die Objekte als Strings vergleichen zu können, reicht es nicht, wenn nirgends Leerzeichen vorkommen, sondern die Darstellung muss grundsätzlich normalisiert sein, also bei den gleichen Zahlenwerten muss sich immer der exakt gleiche String ergeben. Optionale führenden oder folgende Nullen oder unterschiedliche Repräsentationen des Wertes 0 (z.B. als 0, -0 oder <leer>) oder optionale Tausender- oder unterschiedliche Dezimaltrenner usw. darf es also alles nicht geben.
herbivore