JavaScriptオブジェクトの重複を減らします
-
30-09-2019 - |
質問
次のようなオブジェクトがあります。
{
a : 'foo',
b : 'bar',
c : 'foo',
d : 'baz',
e : 'bar'
}
次のような複製を減らしたいです。
{
ac : 'foo',
be : 'bar',
d : 'baz'
}
それをする良い方法は何ですか?
いくつかの注意事項:
- 少数のペアしかありません。 (現在7つあります。たとえば、20まで上がると想像できます。)
- 最初のプロパティ名は、例のように、これまでに1つの文字にしかなりません
- 値は潜在的に数百文字に実行される可能性があります。
- 速度とコードの両方の長さは非常に重要ですが、小数が少ないことを考えると、おそらくコードの明確さが依然として最も重要です。
解決
オブジェクトの各プロパティを通過し、構築します 別 キーは最初の値であり、値はキーのリストです(最初から)。次に、その2番目のオブジェクトを通過して最終結果を作成します。
このようなもの:
function noDupes(obj) {
var o2 = {};
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
var list = o2[obj[k]] || [];
list.push(k);
o2[obj[k]] = list;
}
}
var rv = {};
for (k in o2) {
if (o2.hasOwnProperty(k))
rv[o2[k].join('')] = k;
}
return rv;
}
これで、元のオブジェクトの値が文字列ではない場合、物事はより関与します。文字列のみがJavaScriptオブジェクトのプロパティキーになります。その場合、より一般的なハッシュの実装を探し回ることができます。あなたのオブジェクトがかなり小さい傾向がある場合(10程度のプロパティ以下)、nを書き上げることができます2 バージョンでは、単にプロパティを繰り返してから、それぞれを再度繰り返します。しかし、それはおそらくあなたのオブジェクトが大きく、この操作をたくさん実行する必要がある場合、おそらく悪い考えでしょう。
他のヒント
var Reduce = function(obj)
{
var temp = {};
var val = "";
for (var prop in obj)
{
val = obj[prop];
if (temp[val])
temp[val] = temp[val] + prop.toString();
else
temp[val] = prop.toString();
}
var temp2 = {};
for (var prop in temp)
{
val = temp[prop];
temp2[val] = prop.toString();
}
return temp2;
};
使用:
var obj = {
a :"foo",
b : "bar",
c : "foo",
d : "bar",
e : "bar"
};
var ob2 = Reduce(obj);
これは私がそれを手に入れることができる最短です:
var obj, newObj = {}; // obj is your original
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
for (var j in newObj) {
if (newObj.hasOwnProperty(j) && newObj[j] === obj[i]) break;
j = "";
}
newObj[i + j] = obj[i];
j && delete newObj[j];
}
説明:
- 元のオブジェクトの各アイテムをループし、
obj
, 、そして新しいオブジェクトを生成します、newObj
. - オリジナルの各アイテムについて、それはハーフプロデュースを検索します
newObj
同じ値のために。 - 結果は次のとおりですj
, 、見つかった場合はプロパティの名前、またはそうでない場合は空の文字列のいずれかです。 - どちらの場合でも、新しいオブジェクトには、元のオブジェクトの現在のプロパティと同じ名前のプロパティが必要です。
j
. - また、見つかったプロパティを削除します
newObj
ある場合は、複製が構築されないようにします。
確かに、設定 j = ""
ループ内は非効率的です。これは、2番目の変数設定で簡単に置き換えることができます ""
最初は、そして j
一致が見つかった場合のみ。しかし、私は簡単にすることにしました。
高くなるライブラリがないだけで、各ペアをループするだけです(使用してください hasOwnProperty
)およびヒストグラムキーがペア値であり、ヒストグラム値が連結キーであるヒストグラムにキーを追加/追加します。次に、ヒストグラムのキー/値を逆にします。
編集: 初期値が文字列ではない場合(そして可逆的にマッピングしないでください)、既存の「アイデンティティハッシュ」ライブラリは、上記のアプローチを機能させる可能性があります。
または、マッピングして言うことができます。 [[k,v],...]
並べ替えて、次のようなアプローチを使用します バケットソート (すでにソートされていると想像してください)出力パスの「等しいキー」の値をマージします。
このようになるかもしれません(コードにはバグがあるかもしれませんが、アプローチは健全です - 値を比較する方法がある限り、値として任意のオブジェクトでも機能します):
var _f = []
for (var k in map) {
if (map.hasOwnProperty(k)) {
_f.push({k: k, v: map[k]})
}
}
// you could also sort on name (a.k), if it's important
// this makes it more versatile and deterministic in output
// ordering than the histogram method above
var f = _f.sort(function (a, b) { return a.v < b.v ? 1 : a.v > b.v ? -1 : 0 })
var res = {}
var prev
var name = ""
// after the sort all {k:,v:} objects with the same values will be grouped
// together so we only need to detect the change to the next value
// and everything prior to that gets the merged key
for (var i = 0; i < f.length; i++) {
var p = f[i]
if (prev != p.v && name) {
res[name] = prev
name = ""
} else {
name = name + p.k
}
prev = p.v
}
if (name) { // don't forget last set of values
res[name] = prev
}
// have res
私が完全に外出している場合は私を許してください。しかし、あなたがこれらを組み合わせている方法、あなたはキーと価値が間違っているようになっているように思えます。これはどうですか?
{
'foo': ['a', 'c'],
'bar': ['b', 'e'],
'baz': ['d']
}
変換するのに十分簡単でなければなりません:
flippedObj = {};
for (var letter in obj) {
if (obj.hasOwnProperty(letter)) {
var letters = flippedObj[obj[letter]];
if (letters === undefined) {
letters = [];
flippedObj[obj[letter]] = letters;
}
letters.push(letter);
}
}
(脳がコンパイルされた;いくつかのエラーがあるかもしれません。)
辞書を使用してタグをひっくり返した方法でカウントするRecoseから始めます。組み込みの辞書サポートを使用しているため、非常にパフォーマンスのある方法で、ループなどはありません。
var flipped = Object.keys(input).reduce(function(a,b){
var tag = input[b];
a[tag] = (a[tag] || '') + b;
return a;
}, {});
フリップフォーマットでオブジェクトを返します。
// {foo: "ac", bar: "be", baz: "d"}
次に、フォーマットをフリップするだけです。
Object.keys(flipped).reduce(function(a,b){
a[flipped[b]]=b;
return a;
}, {});
出力:
// {ac: "foo", be: "bar", d: "baz"}