Collections Collection<> mit List<String> abgleichen?

Kel

Aktives Mitglied
Ich habe eine vorgegebene Collection<token> durch ein Framework (dürften String-Objekte sein) und muss diese mit zwei Wortlisten abgleichen - diese haben ~6000 Zeilen.
Wortlisten werden aktuell mittels File.readnextLine(Wortliste.txt) in List<String> und dann in ein String[]-Array umgewandelt.

Erster Ansatz: über die Collection<token> iterieren und dann einfach Collection mit String[]-Array abgleichen.
Dauert aber Ewigkeiten auf dem Unirechner (über 7 Minuten).

Zweiter Ansatz: Collection<token>.toArray = Token[]-Array und dann String[]-Array mit String[]-Array abgleichen.
Dauert aber auch noch ~2 Minuten.

Dritter Ansatz: List<String> in Hashset umwandeln und dann mit Collection<token> oder Token[]-Array vergleichen (da hab ich aber noch absolut 0 Ahnung, war eine Idee meines Dozenten) :rtfm:.
Hashset kümmert sich ja nicht um Sortierung und ich muss ja nur schauen ob der Token-String in der Wortliste vorhanden ist, nicht wo genau er ist.

Hat jemand noch andere Ideen? Code kann ich aktuell leider nicht posten da das SVN mich nicht commiten lässt und die Daten alle auf dem Uni-Rechner liegen. Kann ich morgen nachreichen.
 
Zuletzt bearbeitet:

Gucky

Top Contributor
Ich würde zuerst die Länge der drei Collections (List erbt von Collection) vergleichen. Sind die verglichenen nicht gleich lang, können sie schon mal nicht gleich sein.

Dannn würde ich alle Collections sortieren. Dafür gebe ich dir als Tipp, weil es schnell gehen muss, den Quicksort Algorithmus. Oder es gibt schön Methoden dafür in der Arrays Klasse. Das weiß ich nicht.
Dann wandelst du alle zu vergleichenden Collections in Arrays um. Denn bei ~12.000 Verzweigungen zu irgendeiner anderen Methode, die dann noch mehrere Bereichsprüfungen durchführt, kostet das irgendwann ziehmlich viel Zeit.
Danach vergleichst du die drei miteinander.
 

Kel

Aktives Mitglied
Warum sollte ich alle Collections sortieren?
Und warum sollten alle Collections gleich lang sein? Die Wortlisten sind unterschiedlich groß und die Tokens werden pro Durchlauf pro Zeile (durch das Framework vorgegeben) durchgereicht, das sind 6408 Durchläufe = 6408 Zeilen, wo dann jedes Wort in der Zeile mit den Wortlisten abgeglichen wird.
Die werden also nie alle gleich groß sein? :bahnhof:

Ich muss ja nur die tokens aus der Collection<token> mit den Wortlisten abgleichen, also ob der token in der Wortliste enthalten ist - die genaue Position in der Wortliste ist für mich ja unwichtig?
 
Zuletzt bearbeitet:

stg

Top Contributor
Weil du nach dem Sortieren in quasilinearer Zeit anschließend in linearer Zeit vergleichen kannst.
Vergleichst du ohne vorher zu sortieren, bist du bereits bei quadratischer Laufzeit.
 

Kel

Aktives Mitglied
Vergleichst du ohne vorher zu sortieren, bist du bereits bei quadratischer Laufzeit.
Waren nicht genau dafür Hashsets, wo nur (effizient) abgefragt wird: Hashset(Wortliste1).contains(token) Ja/Nein?

Das Framework arbeitet leider so, dass bei jedem Durchlauf alles komplett neu gemacht wird - Wortlisten einlesen, umwandeln und abgleichen. Also immer mit riesigem Overhead.
Es würde also auch 6408x sortiert werden.

Ich habe nur Java-Grundlagen an der Universität gelernt, die ganzen Sachen jetzt muss ich mir selber beibringen, also schonmal 'Tschuldigung für die ganzen Fragen.
 
Zuletzt bearbeitet:

Gucky

Top Contributor
Ist die übegebene Collection jedes Mal gleich? Dann lass dir doch einfach die Collection geben und arbeite dann damit weiter, anstatt sie dir immer neu geben zu lassen. Oder überschreib die Methode zum übergeben der Collection, so, dass sie nicht immer neu erstellt wird. (Klasse von der Framework Klasse erben lassen)

Eine Faustregel: Brute Force ist nie gut. Es gibt (fast) immer bessere Möglichkeiten.
 

Kel

Aktives Mitglied
Nein, die Collection<token> wird zeilenweise eingelesen und ändert sich mit jedem Durchlauf.
Am Framework was ändern geht nur extrem begrenzt, das hat eine eigene Pipeline und alles, da kann ich den Ablauf nicht beeinflussen :noe: (oder wenn es gehen würde übersteigt es meine Fähigkeiten bei weitem).
Ist JCAS nebenbei, für Textanalysen.

Was mir noch eingefallen ist und was ich wohl ziemlich falsch beschrieben habe - ich muss ALLE Elemente aus der Collection<token> mit den 2 Wortlisten abgleichen.
Aber jedes token EINZELN überprüfen.

Also kein direkter Vergleich von Collection und List, sondern ein Element aus der Collection<token> mit jedem Element aus List<String>.
Und das ganze dann für ~15-20 Token pro Durchgang mit 6408 Durchgängen.
 
Zuletzt bearbeitet:

Gucky

Top Contributor
Ach so.
Dann hätte ich noch eine Idee: bricht die Überprüfung irgendwann ab oder musst du so oder so deinen Wert mit allen Werten aus der Liste vergleichen?
 

Kel

Aktives Mitglied
Der token muss jedesmal die komplette Wortliste durchlaufen, bis zur letzten Zeile

(geht um semantische Textanalyse, einfach Positiv-/Negativ-Wortliste, für jedes positive Wort gibts ein pos++, beim Durchlauf mit der negativen Liste ein neg++ und was am Ende höher ist ist dann das "Sentiment" - pos == neg wird dann neutral) :rtfm:.

Aktuell stecke ich die Wortlisten (List<String) in ein Hashset und frage dann mittels
Java:
 public int tokenCompareWordListSet(Collection<Token> tokens, Set<String> wordList, JCas jcas) {
	   int number = 0;
	   //iterates over the tokens
	   for (Token token : tokens) {
		   if (wordList.contains(token));
		   		number++;
		   
	   }
           return number;
ab.

Aber im Vergleich zu meiner String[] - Abgleich - String[] fehlen mir auf einmal knapp 9% Erkennungsleistung :eek:.
 
Zuletzt bearbeitet:

Gucky

Top Contributor
Noch mal von Vorne, weil sich der Code und deine Ausführungen IMHO wiedersprechen. :)

Du hast eine Liste (A), randvoll mit Tokens. Dann hast du eine andere Liste (B), in denen auch Tokens sind. Dann nimmst du ein Token aus A und guckst, ob es in B enthalten ist. Wenn ja, zählst du einen Wert hoch, wenn nein zählst du einen anderen Wert hoch. Soweit richtig?
 

Kel

Aktives Mitglied
Nicht ganz richtig, aber ich hab es wohl auch falsch beschrieben.

Es wird pro Durchlauf eine Zeile aus einer Textdatei gelesen - diese werden per Framework in Tokens zerhäckselt (sind keine Strings sondern Objekte).
Dann werden 2 Wörterlisten eingelesen als List<String>.

Nun muss ich schauen, ob die Tokens in der Wörterliste enthalten sind. tokens.getCoveredText() sollte mir den spezifischen Text als String zurückgeben.

Das Laufzeitproblem habe ich inzwischen gelöst - das Framework bietet mir mit
Java:
@Override
    public void initialize(UimaContext context)
        throws ResourceInitializationException
    {
        super.initialize(context);        
     // do something
    }
die Möglichkeit, Dinge nur beim ersten Aufruf festzulegen - da habe ich die Dateizugriffe für die Wörterlisten reingehauen, damit die nicht 6408x sondern nur 1x geladen werden :applaus:.
Senkte meine Ausführungszeit von 2-3 Minuten auf wenige Sekunden.

Java:
    // File in List<String>-Object
    public String[] WordListReadArray(File file) {
    	try {
    		importWordList = FileUtils.readLines(file);
    	} catch (IOException e) {
    		System.out.println("File " + importWordList + " failed to load");
    	}
    	// List<String> to String[]-Array
    	String[] liste = new String[importWordList.size()];
    	for (int i = 0; i < importWordList.size(); i++) {
    		liste[i] = importWordList.get(i);
    	}
    	System.out.println(liste.length);
    	return liste; 
   }
Java:
 // ### DAUERT 10 SEKUNDEN ###
    // Durch Token[]-Array "twitter" iterieren und Counter hochzählen
    public int tokenCompareWordListArray(Collection<Token> tokens, String[] wordList, JCas jcas) { 
 	    Token[] twitter = new Token[0];
     	twitter = tokens.toArray(twitter);
 	   int number = 0;
 	   //iterates over the tokens
 	   for (int i = 0; i < twitter.length; i++) {
 		   //tweet-Token
 		   CharSequence token = jcas.getDocumentText().subSequence(twitter[i].getBegin(), twitter[i].getEnd());
 		   //token to String
 		   String tweet = token.toString().toLowerCase();
 		   // iterate through wordList
 		   for(int k = 0; k < wordList.length; k++) {
 			   // compare token-String with wordList-String
 			   if (tweet.equals(wordList[k])) {
 				   //System.out.println(wordList[k] + " found at Token: " + i + " , rated as!");
 				   // increase number for counter();	
 				   number++;
 				   break;
 			   }
 		   }
     }
     return number;
    }
Damit habe ich 58,1% Erkennungsleistung.

Nun wollte ich das ganze mal mit einem Hashset machen :rtfm:.
Java:
// File in List<String>-Object # ONLY ONCE IN INSTANCE METHOD
    public Set<String> WordListReadSet(File file) {
    	try {
    		importWordList = FileUtils.readLines(file);
    	} catch (IOException e) {
    		System.out.println("File " + importWordList + " failed to load");
    	}
    	Set<String> set = new HashSet<String>(importWordList);
    	System.out.println(importWordList.size());
    	return set;    
   }
Java:
 // ### 7 Seconds ### 8,71% WENIGER ERKENNUNG WIESO??
    // Durch Collection<token> iterieren und Counter hochzählen bei Treffer
    public int tokenCompareWordListSet(Collection<Token> tokens, Set<String> wordList, JCas jcas) {  
 	   int number = 0;
 	   //iterates over the tokens, looks if token is contained in wordList
 	   for (Token token : tokens) {
 		   if (wordList.contains(token.getCoveredText().toLowerCase()));
 		   		number++; }	
     return number;
    }
Auf einmal fehlen mir aber 8,23% - ich habe nur 43,39% Erkennungsleistung ..... :cry:.

Bin für jede Hilfe dankbar.
 
Zuletzt bearbeitet:
Ähnliche Java Themen

Ähnliche Java Themen


Oben