2016-12-10 92 views
2

我試圖操縱這個樣本數組的對象。合併對象連接值,使用lodash

[ { name: 'John Wilson', 
    id: 123, 
    classes: ['java', 'c++']}, 
    { name: 'John Wilson', 
    id: 123, 
    classes: 'uml'}, 
    { name: 'Jane Smith', 
    id: 321, 
    classes: 'c++'} ] 

我需要做的是合併具有相同'id'的對象,連接'classes'並保留一個'name'。

結果應該是:

[ { name: 'John Wilson', 
    id: 123, 
    classes: ['java', 'c++', 'uml']}, 
    { name: 'Jane Smith', 
    id: 321, 
    classes: 'c++'} ] 

我嘗試使用.merge,但它不會從「類」拼接價值,它只是不斷從上次相同對象的值。

使用lodash做到這一點最簡單的方法是什麼?

回答

2

你要找的功能是_.uniqWith,有一個特殊的扭曲我會在一分鐘內解釋。

_.uniqWith_.uniq很相似,它會生成一個唯一的數組,但它允許您傳遞自己的自定義比較函數,該函數將被調用以確定什麼是「相等」。

Sane程序員會理解這個比較器應該是無副作用的。該代碼的工作方式是通過打破該規則,並使用在幕後執行額外魔法的比較函數。但是,這會產生非常簡潔的代碼,無論這些對象中有多少個都可以工作,所以我覺得違規行爲是合理的。

我將比較函數compareAndMerge命名爲不隱藏其不純性質。它將合併兩個classes數組並更新兩個對象上的相關屬性,但前提是它們的id值相同。

function merge(people) { 
 
    return _.uniqWith(people, compareAndMerge) 
 
} 
 

 
function compareAndMerge(first, second) { 
 
    if (first.id === second.id) { 
 
     first.classes = second.classes = [].concat(first.classes, second.classes) 
 
     return true 
 
    } 
 
    return false 
 
} 
 

 

 
var people = [{ 
 
    name: 'John Wilson', 
 
    id: 123, 
 
    classes: ['java', 'c++'] 
 
}, { 
 
    name: 'John Wilson', 
 
    id: 123, 
 
    classes: 'uml' 
 
}, { 
 
    name: 'Jane Smith', 
 
    id: 321, 
 
    classes: 'c++' 
 
}] 
 

 
console.log(merge(people))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>

旁白:你在你原來的classes名單缺少方括號。儘管如此,我確信上面的代碼並不關心classes屬性是否包含單個字符串或字符串數​​組。

+0

謝謝!其實我忘了括號。代碼很乾淨,效果很好。 –

+0

很高興幫助!我也學到了很多關於習慣的東西。 – gyre

0

不知道使用lodash ......這裏的方式與正常JS做到這一點:

var combined = arr.reduce(function(a, item, idx) { 
    var found = false; 
    for (var i = 0; i < a.length; i++) { 
     if (a[i].id == item.id) { 
      a[i].classes = a[i].classes.concat(item.classes); 
      found = true; 
      break; 
     } 
    } 

    if (!found) { 
     a.push(item); 
    } 

    return a; 
}, []); 

小提琴:https://jsfiddle.net/6zwr47mt/

0

使用_.mergeWith設置合併定製

_.reduce(data, function(result, item) { 
    item = _.mergeWith(
     item, 
     _.find(result, {id: item.id}), 
     function(val, addVal) { 
      return _.isArray(val) ? _.concat(val, addVal) : val; 
     }); 
    result = _.reject(result, {id: item.id}) 
    return _.concat(result, item); 
}, []); 
0

下面的算法是不是最好的,但至少我知道它做什麼:-)

console.log(clean(data)); 
 

 
function clean (data) { 
 
    var i, x, y; 
 
    var clean = []; 
 
    var m = clean.length; 
 
    var n = data.length; 
 
    data.sort((x, y) => x.id - y.id); 
 
    for (i = 0; i < n; i++) { 
 
    y = data[i]; 
 
    if (i == 0 || x.id != y.id) { 
 
     clean.push(x = clone(y)), m++; 
 
    } else { 
 
     clean[m - 1] = merge(x, y); 
 
    } 
 
    } 
 
    return clean; 
 
} 
 

 
function clone (x) { 
 
    var z = {}; 
 
    z.id = x.id; 
 
    z.name = x.name; 
 
    z.classes = x.classes.slice(); 
 
    return z; 
 
} 
 

 
function merge (x, y) { 
 
    var z = {}; 
 
    z.id = x.id; 
 
    z.name = x.name; 
 
    z.classes = unique(
 
    x.classes.concat(y.classes) 
 
); 
 
    return z; 
 
} 
 

 
function unique (xs) { 
 
    var i, j, n; 
 
    n = xs.length; 
 
    for (i = 1; i < n; i++) { 
 
    j = 0; while (j < i && xs[i] !== xs[j]) j++; 
 
    if (j < i) swap(xs, i, n - 1), i--, n--; 
 
    } 
 
    return xs.slice(0, n); 
 
} 
 

 
function swap (xs, i, j) { 
 
    var x = xs[i]; 
 
    xs[i] = xs[j]; 
 
    xs[j] = x; 
 
}
<script> 
 
    var data = [{ 
 
    id: 123, 
 
    name: 'John Wilson', 
 
    classes: ['java', 'c++'] 
 
    }, { 
 
    id: 123, 
 
    name: 'John Wilson', 
 
    classes: ['uml', 'java'] 
 
    }, { 
 
    id: 321, 
 
    name: 'Jane Smith', 
 
    classes: ['c++'] 
 
    }]; 
 
</script>

1

使用ES6你可以用Map這樣做來保存唯一值Array#reduce popu晚了,和spread operatorMap#values將其轉換回陣列:

const arr = [{"name":"John Wilson","id":123,"classes":["java","c++"]},{"name":"John Wilson","id":123,"classes":"uml"},{"name":"Jane Smith","id":321,"classes":"c++"}]; 
 

 
const result = [...arr.reduce((hash, { id, name, classes }) => { 
 
    const current = hash.get(id) || { id, name, classes: [] }; 
 
    
 
    classes && (current.classes = current.classes.concat(classes)); 
 
    
 
    return hash.set(id, current); 
 
}, new Map).values()]; 
 

 
console.log(result);

+0

這真的很聰明,很有創意。瞭解內部和外部ES6的+1。 – gyre