Laden...

Aus String doppelte Einträge entfernen (solved)

Erstellt von squadwuschel vor 16 Jahren Letzter Beitrag vor 16 Jahren 11.695 Views
S
squadwuschel Themenstarter:in
406 Beiträge seit 2007
vor 16 Jahren
Aus String doppelte Einträge entfernen (solved)

Hio,

Wollte mal fragen wie ich aus seinem String am besten doppelte Einträge entfernen kann und vor allem effektiv.

Im Moment löse ich es so und es dauert "ewig":


 public string getTextStichworte3(string text)
    {
        //filtert aus dem übergebenen Text doppelte Wörter heraus, so das eine Stichwortsuche daraus entsteht
        //und jedes Wort nur noch einmal in dem Text vorkommt

        StringBuilder stichworttext = new StringBuilder();

        //Herausfiltern von doppelten Einträgen

        string temp = "";
        while (text.ToString().Length != 0)
        {
            try
            {
                temp = text.Substring(0, text.IndexOf(' ')).Trim();
                stichworttext.Append(temp + " ");
                text = text.Remove(0, text.IndexOf(' '));
                text = text.Replace(" " + temp + " ", " ");
                text = text.Trim();
            }
            catch
            {
                stichworttext.Append(text);
                break;
            }
            
        }

        return stichworttext.ToString();
    }

jmd eine gute idee und evtl. noch ein wenig code dazu wäre nice 🙂

aus dem string test = "Hallo ich bins und der hund und die Katze und der Hase"
wird --> "Hallo ich bins der Hund die katze Hase und"

Mein Blog über .NET und MVC / EF | Meine kostenlose Onlinearbeitszeitverwaltung My:Worktime

A
138 Beiträge seit 2007
vor 16 Jahren

Hallo,
bist du dir sicher, dass aus deinem String das richtige resultiert? Was passiert mit dem und?

würde es so machen:
Wörter nacheinander abarbeiten (entweder direkt per split beim Leerzeichen trennen oder den Zeiger, den es so ja nicht mehr gibt, immer zum nächsten Leerzeichen weiterlaufen lassen).
Dann in einer Hashtable speichern, ob das Wort schon vorhanden ist, wenns schon vorhanden ist nichts weiter machen, wenn noch nicht, dieses Wort der Hashtable hinzufügen und an einen StringBuilder anhängen (zzgl. Leerzeichen).

Das ganze mit dem StringBuilder kann entfallen, sofern du nur die einzelnen Wörter brauchst und keinen neuen String

369 Beiträge seit 2006
vor 16 Jahren

Immer noch nicht die Beste Performance, aber deutlich besser als dein Code:


string[] tokens = inputString.Split(' ');

// Hashset wäre besser geeignet, Dictionary geht auch
IDictionary words = new Dictionary<string, string>(tokens.Length);

// Achtung: O(n)
foreach (string token in tokens)
{
  if (!words.ContainsKey(token))
    words.Add(token, token);
}

// words enthält nun jedes Wort genau einmal
// ein Array lässt sich daraus folgendermaßen erstellen; Achtung: O(n)

string[] wordsArray = new string[words.Count];
words.Values.CopyTo(wordsArray, 0);

// so erstellst du wieder einen string; Annahme, dass ein durschnittliches Wort (einschließlich dem nachfolgenden Leerzeichen) aus sieben Zeichen besteht. Durch schätzen der Länge des fertigen Strings lässt sich die Performance erhöhen. Über die Verwendung eines genaueren Durchschnittswerts sollte nachgedacht werden.

StringBuilder keywordsBuilder = new StringBuilder(inputString.Length - 7 * (tokens.Length - words.Count));

// Achtung O(n)
foreach (string keyword in words.Values)
{
  keywordsBuilder.Append(keyword);
  keywordsBuilder.Append(" ");
}

// letztes Leerzeichen entfernen
keywordsBuilder.Remove(keywordBuilder.Length - 1, 1);

S
squadwuschel Themenstarter:in
406 Beiträge seit 2007
vor 16 Jahren

ok werde ich morgen mal versuchen muss gestehen mit List bzw. Dictionary habe ich noch garkeine erfahrungen gemacht und kenne diese elemente auch nicht wirklich. bzw. list habe ich schonmal in c++ eine erstelle ^^ .

p.s. das "und" hatte ich vergessen ^^ in meinem string.

mfg squadwuschel

Mein Blog über .NET und MVC / EF | Meine kostenlose Onlinearbeitszeitverwaltung My:Worktime

49.485 Beiträge seit 2005
vor 16 Jahren

Hallo

die Performance dieser Schleife


foreach (string token in tokens)
{
  if (!words.ContainsKey(token))
    words.Add(token, token);
}

kann man noch ungefähr verdoppeln:


foreach (string token in tokens)
{
    words [token] = token;
}

An der Größenordnung O (n) ändert das allerdings nichts.

herbivore

57 Beiträge seit 2006
vor 16 Jahren

Deine Stichwortsuche hört sich nach einer einfachen "Volltextsuche" an. Deshalb würde ich auf jeden Fall noch die Stoppwörter entfernen, d.h. die nicht sinntragenden Wörter, die Deinen Stichwortindex nur unnötig aufblähen. Das wären z.B. im Normalfall alle bestimmten / unbestimmten Artikel oder Konjunktionen.

Nur mal als Vorschlag

banzai

2 + 2 = 5 for large values of 2

3.971 Beiträge seit 2006
vor 16 Jahren

Mit Regex kann man auch sehr gut doppelte Wörter oder Buchstabenkombis entfernen

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

S
squadwuschel Themenstarter:in
406 Beiträge seit 2007
vor 16 Jahren

ja ist richtig sollten am ende alle nicht "sinnvollen" wörter nicht mehr enthalten sein.

was ist regex ?

mfg squadwuschel

Mein Blog über .NET und MVC / EF | Meine kostenlose Onlinearbeitszeitverwaltung My:Worktime

664 Beiträge seit 2005
vor 16 Jahren

Original von squadwuschel
was ist regex ?

Reguläre Ausdrücke / Regular Expressions.
Bitte solche Stichworte selbst nachschlagen.

3.971 Beiträge seit 2006
vor 16 Jahren

Schau dir am besten mal Regex Tutorial an.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

S
squadwuschel Themenstarter:in
406 Beiträge seit 2007
vor 16 Jahren

werde ich machen, bisher leider noch nicht dazu gekommen, das auszutesten, noch andere Softwareprobleme ^^

vielen dank erstmal für die vielen antworten

Mein Blog über .NET und MVC / EF | Meine kostenlose Onlinearbeitszeitverwaltung My:Worktime

K
5 Beiträge seit 2007
vor 16 Jahren
C#: Count words

private string CountWords(string input)
        {
            char[] delims = new char[]{ ' ', '.', ',',';' };
            string[] wordlist = input.Split(delims , StringSplitOptions.RemoveEmptyEntries);
            SortedList<string,int> words = new SortedList<string,int>();
            //Dictionary<string, int> words = new Dictionary<string, int>(wordlist.Length);
            foreach (string item in wordlist)
            {
                if (!words.ContainsKey(item))
                    words.Add(item, 1);
                else
                    words[item]++;
            }
            StringBuilder sb = new StringBuilder();
            foreach (KeyValuePair<string,int> kvp in words)
                sb.Append(kvp.Key + ": " + kvp.Value + "\r\n");
            //foreach (string item in words.Keys)
            //    sb.Append(item + ": " + words[item] + "\r\n");
            return sb.ToString();
        }

maybe this is an option for counting words with few lines of code.

keoma

S
squadwuschel Themenstarter:in
406 Beiträge seit 2007
vor 16 Jahren

hio,

also habe ich mal getestet und ist ja krass wie schnell das geht im gegensatz zu meiner ersten lösung wo es teilweise bei großen Dokumenten bis zu 5 min dauern konnte dauert es jetzt maximal noch so 20 sek ^^.

Habe aber mal noch eine kleine Frage zum code.

Den Code verstehe ich ja noch er überprüft ob das angebene Wort in der Collection enthalten ist und wenn nicht wird dieses mit add hinzugefügt.


foreach (string token in tokens)
{
  if (!words.ContainsKey(token))
    words.Add(token, token);
}

Doch das verstehe ich nicht mehr wirklich, ich würde sagen wenn das wort bereits enthalten ist, wird dieses ersetzt. aber wie wird ein neues eingefügt? oder verstehe ich die Syntax falsch?


foreach (string token in tokens)
{
    words [token] = token;
}

bzw. warum entfernt man wörter wie "die", "und", ... nicht einfach mit, sondern nimmt regex ?


Replace("die", "");
...

mfg squadwuschel

Mein Blog über .NET und MVC / EF | Meine kostenlose Onlinearbeitszeitverwaltung My:Worktime

49.485 Beiträge seit 2005
vor 16 Jahren

Hallo squadwuschel,

Doch das verstehe ich nicht mehr wirklich, ich würde sagen wenn das wort bereits enthalten ist, wird dieses ersetzt. aber wie wird ein neues eingefügt? oder verstehe ich die Syntax falsch?

bei "meiner" Syntax wird der Wert hinzugefügt, wenn der Key noch nicht vorhanden ist und überschrieben, wenn er schon vorhanden ist. Es ist also nicht nötig, vorher extra zu prüfen, ob der Key schon vorhanden ist.

warum entfernt man wörter wie "die", "und", ... nicht einfach mit, sondern nimmt regex ?

Regex kann man benutzen, wenn man z.B. doppelte Wörter nach dem Muster Muster im Text vorhanden vorhanden sind und man diese entfernen möchte. Für das, was du machen willst, ist Regex unpassend. Wie du schon richtig sagst, würde man einfach alle Stoppworte am Ende aus dem Dictionary rauslöschen.

herbivore

S
squadwuschel Themenstarter:in
406 Beiträge seit 2007
vor 16 Jahren

ok danke dir 🙂

achso hast du evtl. einen link wo das dictionary etwas genauer erklärt ist was das genau macht? Vor allem warum es 2 werte hat die beide gleich heissen? Habe zwar schon einige Bücher durchsucht aber nichts genaues über die Funktionsweise von dictionaries gefunden. Nur das es sich um "listen" handelt welche ein paar "spezielle" fähigkeiten bieten wie contains abfrage usw.

mfg squadwuschel

Mein Blog über .NET und MVC / EF | Meine kostenlose Onlinearbeitszeitverwaltung My:Worktime

49.485 Beiträge seit 2005
vor 16 Jahren

Hallo squadwuschel,

achso hast du evtl. einen link wo das dictionary etwas genauer erklärt ist was das genau macht? [Artikel] Grundlegendes zu Hashtable/Dictionary

Vor allem warum es 2 werte hat die beide gleich heissen?

Was für zwei Werte, die gleich heißen? Ein Dictionary enthält zu einem Key immer genau einen Wert. Es enthält KeyValuePairs und zwar so, dass jeder Key immer nur genau einmal vorkommt.

herbivore

369 Beiträge seit 2006
vor 16 Jahren

Im Bsp sind Schlüssel und Wert identisch. Die Verwendung eines Dictionary anstelle einer gewöhnlichen Liste ermöglicht jedoch das auffinden von enthaltenen objekten mit einer operation der Größenordnung O(1).

S
squadwuschel Themenstarter:in
406 Beiträge seit 2007
vor 16 Jahren

hio nochmal habe mir mal deinen Artikel durchgelesen und noch eine kleine Frage du hast bei dir so etwas wie:

words["die"] = false

geschrieben, nur das verstehe ich nicht ganz in wie weit das funktioniert, bzw. bei mir schmiert er mir da z.b. ab, wenn ich das noch mit einbaue nachdem ich in words alle wörter gespeichert habe und nun z.b. "die" daraus entferne will. Habe ich da etwas falsch verstanden ?

ich meine so:

words["die"] = "";

geht es ja, wäre das effektiver als Remove ?

mfg squadwuschel

Mein Blog über .NET und MVC / EF | Meine kostenlose Onlinearbeitszeitverwaltung My:Worktime

49.485 Beiträge seit 2005
vor 16 Jahren

Hallo squadwuschel,

words["die"] = false

[...] bei mir schmiert er mir da z.b. ab,

das glaube ich kaum. Ich denke, der Compiler meckert da einfach: Da du ein Dictionary<String,String> hast, kannst du nur Strings als Werte verwenden. Ich verwende ein Dictionary<String, bool> und weise entsprechend bools zu.

words["die"] = "";

geht es ja, wäre das effektiver als Remove ?

Ich gehe davon aus, dass sich beides performancemäßig nicht viel nimmt. Ist eher Geschmackssache.

herbivore

S
squadwuschel Themenstarter:in
406 Beiträge seit 2007
vor 16 Jahren

ahso

ok danke nochmals für die viele Hilfe.

mfg squadwuschel

Mein Blog über .NET und MVC / EF | Meine kostenlose Onlinearbeitszeitverwaltung My:Worktime