2011-01-06 35 views
5

我已經有了喜歡的對象:減少重複的JavaScript物件

{ 
    a : 'foo', 
    b : 'bar', 
    c : 'foo', 
    d : 'baz', 
    e : 'bar' 
} 

我想要減少重複的:

{ 
    ac : 'foo', 
    be : 'bar', 
    d : 'baz' 
} 

怎樣做一個好辦法嗎?

幾個注意事項:

  • 將有永遠只能是對一個小數目。 (目前有7個;我可以想象它會延長到20)。
  • 最初的屬性名稱將只會是單個字符,例如
  • 這些值可能會運行到幾百個字符。
  • 速度和代碼長度都非常重要,但考慮到行數很少,代碼清晰度可能仍然是最重要的。

回答

0

經過對象的每個屬性和構建另一個對象,其中,所述鍵是所述第一值,以及該值是密鑰的列表(從第一)。然後你回到第二個對象並做出最終結果。

事情是這樣的:

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個屬性),你可以寫出版本,你只需遍歷這些屬性,然後再爲每一個迭代。但是,如果你的對象可能很大並且你必須執行這個操作,那麼這可能是一個糟糕的主意。

+0

我只是wr提出這個想法。但是如果其中一個值不是字符串會發生什麼? – sprugman 2011-01-06 23:10:08

+0

@sprugman啊,這讓事情多一點參與...... – Pointy 2011-01-06 23:11:57

+0

是的,經過測試,如果你有一個對象作爲一個值,那麼你最終結果行像{x:「[object Object]」} – sprugman 2011-01-06 23:22:12

1

如果沒有更高類型的庫只是循環每對(使用hasOwnProperty),並添加/追加到直方圖的關鍵是配對值和直方圖值是串聯鍵的直方圖。然後顛倒直方圖的鍵/值。

編輯:如果初始值不是字符串(並且不能可逆映射),那麼現有的「身份哈希」庫仍然可以使上述方法起作用。

或者,您可以映射到[[k,v],...]並進行排序,然後使用與bucket sort類似的方法(想象它已經排序),以合併輸出過程中的「等於鍵」的值。

它可能是這樣的(而代碼可能有錯誤的做法是合理的 - 它也將與任意對象作爲值的工作,只要你有辦法比較值):

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 
+0

我想我可能需要一個代碼示例,除非你的意思與Pointy相同。 – sprugman 2011-01-06 23:21:09

1
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); 
1

這是最短的,我可以得到它:

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 = ""效率不高。只有在找到匹配項的情況下,才能很容易地將第二個變量替換爲最初的""j。儘管如此,我決定儘量簡化。

0

原諒我,如果我完全失控,但在我看來,你這樣組合的方式,你已經得到了鑰匙和價值觀的錯誤方式。那這個呢?

{ 
    '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); 
    } 
} 

(腦編譯;有可能是一對夫婦的錯誤)

0

先從減少使用字典來算標籤以翻轉的方式。非常高性能的方式,因爲它使用內置的詞典支持,沒有for循環等

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"}