JavaScript Closest Match + Prozent

blablub1212

Rear Admiral
Registriert
Sep. 2009
Beiträge
5.993
Hallo liebes Forum,

leider sind meine Skills beschränkt und ich habe ein Problem, dass ich nicht lösen kann. Leider weder durch logischen überlegen, noch durch Google-Recherche.

Mein Problem ist folgendes:

Ich habe eine Vorgabe-Datensatz (vorgabe) und viele viele Eingaben (eingabe). Ich möchte nun für jede Eingabe überprüfen ob und zu welchem Teil eine Eingabe mit der Vorgabe übereinstimmt.

In dem Beispiel Datensatz ist keine meiner Eingaben 100% identisch mit meiner Vorgabe. Jedoch stimmt bspw. bei id:2 "car" und "bike" mit der Vorgabe überein. Also matchen die vorgabe und eingabe zu 66% und id:3 zu 33%.

Kennt ihr evtl. einen Weg (plain javascript ist kein muss, underscore, jquery etc. ist alles ok) mit dem ich mir für alle Eingaben ausgeben lassen kann zu wieviel Prozent sie mit der Vorgabe übereinstimmen?

Probiert habe ich es bspw. mit indexOf (http://stackoverflow.com/a/21041795) aber das Funktioniert nur mit Arrays und nicht mit Objekten :(

Code:
    var vorgabe = {
      "car": "mercedes",
      "bike": "harley",
      "plane": "dornier"
    };

    var eingaben = [{
      "id": 1,
      "car": "bmw",
      "bike": "suzuki",
      "plane": "airbus"
    }, {
      "id": 2,
      "car": "mercedes",
      "bike": "harley",
      "plane": "turboprop"
    }, {
      "id": 3,
      "car": "audi",
      "bike": "harley",
      "plane": "boeing"
    }];
 
Mit underscore geht das schön per max.
Code:
function findBest() {
    var searchKeys = Object.keys(vorgabe);
    // Maximum über alle Eingaben
    return _.max(eingaben, function (obj) {
        // Summe aller gleichen Keys als Kriterium
        return _.reduce(searchKeys, function (memo, key) {
            return vorgabe[key] === obj[key] ? memo + 1 : memo;
        }, 0);
    });
}
So findet man das erstbeste Element. Es gibt aber keinen Grenzwert. Wenn nichts passt, wird das erste Objekt zurückgegeben, da alle Wert 0 hätten. Sollte man vllt. abfangen. Wenn nichts in der Liste war undefined.
Das manuelle Object.keys könnte man bei underscore wohl weglassen, ist so aber vllt. etwas klarer.

Wenn du die Wertungen speichern willst, kannste einfach per map anstatt max über die eingaben und damit weitermachen.
 
Zuletzt bearbeitet:
Bin auch neu in JavaScript, aber auf Anhieb würde ich es so machen:

Code:
//wenn die Objekt Struktur der Vorgabe und Eingabe gleich ist
function getMatchQuote(pre, input){
	let preVals = Object.keys(pre).map(key => pre[key]);
	let inputVals = Object.keys(input).map(key => input[key]);
	let eq = 0;
	preVals.reverse().forEach(function(preVal){
		if(preVal===inputVals.pop()) eq++;
	})
	return eq*100/preVals.length + '%';
}

eingaben.forEach(function(eingabe){
	console.log(getMatchQuote(vorgabe, eingabe));
})
 
Vielen Dank ihr zwei!

@T0a5tbr0t

Das Matching hat gut funktioniert, auch konnte ich das mit einer Prozent-Angabe erweitern. Jedoch war ich zu blöd, mehr als nur das beste Match auszugeben.

Ich bin aber nun doch einen anderen Weg gegangen um habs wie folgt gemacht: https://jsfiddle.net/md9yfzv3/

Das ist bestimmt ziemlich stümperhaft, aber für das Gimmick was ich damit vorhabe tut es. Als Ergebnis bekomm ich nun ein Array, dass ich in meinem AngularJS Frontend einfach mit OrderBy und Limit so anzeigen lassen wie ich es vor hatte. Die Lösung ist halt nicht super elegant :D
 
Ist überhaupt nicht unelegant :D Entweder speichert man zusätzliche Daten, welche Algorithmen ausspucken, bei den Ursprungsdaten (so hast du es jetzt gemacht) oder in einem extra Bereich (z.B. einer neuen Array). Sofern man den Code gut versteht, würde ich immer Finger von "extra cleveren" Lösungen lassen ;)
Dein Ansatz erspart sogar häufiges neu-erstellen von Objekten.
 
Zurück
Oben