2016-09-06 3 views
2

に同じ二つのオブジェクトコンバイン:私は2つのオブジェクトを結合したい私はオブジェクトの配列を持っているし、配列内のオブジェクトの2が同じである(最後の2)Underscore.js

[ 
     { 
      "facilities": 1, 
      "place": "Campbellsville", 
      "state": "KY", 
      "lat": 37.34595018, 
      "lon": -85.34544564 
     }, 
     { 
      "facilities": 1, 
      "place": "Lexington", 
      "state": "KY", 
      "lat": 38.040584, 
      "lon": -84.503716 
     }, 
     { 
      "facilities": 1, 
      "place": "Hebron", 
      "state": "KY", 
      "lat": 39.066147, 
      "lon": -84.703189 
     }, 
     { 
      "facilities": 1, 
      "place": "Hebron", 
      "state": "KY", 
      "lat": 39.066147, 
      "lon": -84.703189 
     } 
    ] 

をその「施設の各値の合計になるように「施設のキーを持つ1つのオブジェクトに同じです。

[ 
     { 
      "facilities": 2, 
      "place": "Campbellsville", 
      "state": "KY", 
      "lat": 37.34595018, 
      "lon": -85.34544564 
     }, 
     { 
      "facilities": 1, 
      "place": "Lexington", 
      "state": "KY", 
      "lat": 38.040584, 
      "lon": -84.503716 
     }, 
     { 
      "facilities": 2, 
      "place": "Hebron", 
      "state": "KY", 
      "lat": 39.066147, 
      "lon": -84.703189 
     }, 
    ] 

JavaScriptでまたはノードのunderscore.jsを使用してこれを行う方法はありますか?

答えて

0

これは私が同様の問題に対処し、別のスタックオーバーフローの質問から収集機能です。それはjavascriptである。

var compare = function (json1, json2) { 
    var i, l, leftChain, rightChain; 

    function compare2Objects (x, y) { 
     var p; 

     // remember that NaN === NaN returns false 
     // and isNaN(undefined) returns true 
     if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') { 
      return true; 
     } 

     // Compare primitives and functions. 
     // Check if both arguments link to the same object. 
     // Especially useful on the step where we compare prototypes 
     if (x === y) { 
      return true; 
     } 

     // Works in case when functions are created in constructor. 
     // Comparing dates is a common scenario. Another built-ins? 
     // We can even handle functions passed across iframes 
     if ((typeof x === 'function' && typeof y === 'function') || 
     (x instanceof Date && y instanceof Date) || 
     (x instanceof RegExp && y instanceof RegExp) || 
     (x instanceof String && y instanceof String) || 
     (x instanceof Number && y instanceof Number)) { 
      return x.toString() === y.toString(); 
     } 

     // At last checking prototypes as good as we can 
     if (!(x instanceof Object && y instanceof Object)) { 
      return false; 
     } 

     if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) { 
      return false; 
     } 

     if (x.constructor !== y.constructor) { 
      return false; 
     } 

     if (x.prototype !== y.prototype) { 
      return false; 
     } 

     // Check for infinitive linking loops 
     if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) { 
      return false; 
     } 

     // Quick checking of one object being a subset of another. 
     // todo: cache the structure of arguments[0] for performance 
     for (p in y) { 
      if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) { 
       return false; 
      } 
      else if (typeof y[p] !== typeof x[p]) { 
       return false; 
      } 
     } 

     for (p in x) { 
      if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) { 
       return false; 
      } 
      else if (typeof y[p] !== typeof x[p]) { 
       return false; 
      } 

      switch (typeof (x[p])) { 
       case 'object': 
       case 'function': 

        leftChain.push(x); 
        rightChain.push(y); 

        if (!compare2Objects (x[p], y[p])) { 
         return false; 
        } 

        leftChain.pop(); 
        rightChain.pop(); 
        break; 

       default: 
        if (x[p] !== y[p]) { 
         return false; 
        } 
        break; 
      } 
     } 

     return true; 
    } 
    leftChain = []; //Todo: this can be cached 
    rightChain = []; 
    return (!compare2Objects(json1, json2)); 
} 

私は無地のJSにバックボーン(underscore.jsに依存)モデル

3

ソリューションを比較するためにそれを使用します。我々は、重複する項目の配列をループしてチェック基づきます

指定されたキーの値に基づきます。

我々は我々が以前に遭遇した値に遭遇すると、これは我々が重複を見つけた示しています。オブジェクトが新しい場合は、オカレンスを格納します。これまでに見たことがある場合は、2つのオブジェクトをマージし、マージされた表現を保存します。

我々は、参照オブジェクトを使用します、前にすぐに我々は同じオブジェクトを見てきたかどうかを確認することができるようにします。このオブジェクトは、各ユニークキーの項目を保持します。 I定義この例で

  • マージ戦略:このfacilitiesプロップ
  • を比較キーインクリメントの論理保持:をこれが決定するプロパティの名前を保持します2つのオブジェクト間の「類似性」
  • オブジェクトを配列に変換するユーティリティメソッド

// Take an array of objects, compare them by `key`, merge if the `key` 
 
// is not unique, return a new array. 
 
var mergeDuplicatesByKey = function(items, mergeStrat, key) { 
 
    return objValues(items.reduce(function(result, item) { 
 
    var id = item[key]; 
 
    if (!result[id]) { 
 
     result[id] = item; 
 
    } else { 
 
     result[id] = mergeStrat(result[id], item); 
 
    } 
 

 
    return result; 
 
    }, {})); 
 
}; 
 

 
// Our merge strategy: 
 
// - create a new object 
 
// - add all of item1 and item2's properties 
 
// - sum the facilities prop 
 
var merge = function(item1, item2) { 
 
    return Object.assign({}, item1, item2, { 
 
    facilities: item1.facilities + item2.facilities 
 
    }); 
 
}; 
 

 
// The example data: 
 
var data = [{ 
 
    "facilities": 1, 
 
    "place": "Campbellsville", 
 
    "state": "KY", 
 
    "lat": 37.34595018, 
 
    "lon": -85.34544564 
 
}, { 
 
    "facilities": 1, 
 
    "place": "Lexington", 
 
    "state": "KY", 
 
    "lat": 38.040584, 
 
    "lon": -84.503716 
 
}, { 
 
    "facilities": 1, 
 
    "place": "Hebron", 
 
    "state": "KY", 
 
    "lat": 39.066147, 
 
    "lon": -84.703189 
 
}, { 
 
    "facilities": 1, 
 
    "place": "Hebron", 
 
    "state": "KY", 
 
    "lat": 39.066147, 
 
    "lon": -84.703189 
 
}]; 
 

 
// Call merge method with our own strategy, comparing items by `place` 
 
console.log(mergeDuplicatesByKey(data, merge, "place")); 
 

 

 
// Utils: 
 
// Return the values for each key in in an object 
 
function objValues(obj) { 
 
    return Object.keys(obj).map(function(key) { 
 
    return obj[key]; 
 
    }); 
 
};

+0

このソリューションにはECMAScript 2015(ES6)が必要ですが、そうでない場合はObject.assignは機能しませんポリフィル)。とにかく、素晴らしいソリューション、+1。 (また、かなり弾性1つ) – briosheje

+0

@brioshejeそれを追加していただきありがとうございます!古いバージョンをサポートする必要がある人なら、ここでpolyfillを見つけることができます:https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign – user3297291

1

一つの選択肢(つまり、2回の反復を必要とする)(あなたは施設をまとめることができるように)ダウン場所のオフキーオブジェクトへのあなたの配列を減らすことであろう。そこで停止して、生成されたオブジェクトを繰り返し処理するか、合計配列として必要な場合はObject.keysを実行し、各キーに格納されているオブジェクトを返します。

オブジェクトに削減:

var reduced = facilities.reduce(function(p, c) { 
    if (p[c.place]) p[c.place].facilities++; 
    else p[c.place] = c; 
    return p; 
}, {}); 

合計値を取得:複合キーをご希望の場合には何でもにより

Object.keys(reduced).map(function(item) { return reduced[item] }); 

var facilities = [ 
 
    { 
 
    "facilities": 1, 
 
    "place": "Campbellsville", 
 
    "state": "KY", 
 
    "lat": 37.34595018, 
 
    "lon": -85.34544564 
 
    }, 
 
    { 
 
    "facilities": 1, 
 
    "place": "Lexington", 
 
    "state": "KY", 
 
    "lat": 38.040584, 
 
    "lon": -84.503716 
 
    }, 
 
    { 
 
    "facilities": 1, 
 
    "place": "Hebron", 
 
    "state": "KY", 
 
    "lat": 39.066147, 
 
    "lon": -84.703189 
 
    }, 
 
    { 
 
    "facilities": 1, 
 
    "place": "Hebron", 
 
    "state": "KY", 
 
    "lat": 39.066147, 
 
    "lon": -84.703189 
 
    } 
 
]; 
 

 
var reduced = facilities.reduce((p, c) => { 
 
    if (p[c.place]) p[c.place].facilities++; 
 
    else p[c.place] = c; 
 
    return p; 
 
}, {}); 
 

 
console.log(reduced); 
 

 
var summedArray = Object.keys(reduced).map(function(item) { return reduced[item]; 
 
}); 
 

 
console.log(summedArray);

+0

ニース! FWIW私はあなたが '_.values()'(OPアンダースコア.js)で合計値を得ることができると思います。また、 'place'の代わりに' lat + lon'を使ってアイテムをキーします。 – James

1

まず、グループ:

var keyDel = '|'; 
var groups = _.groupBy(list, function(value){ 
    return value.place + keyDel + value.state + keyDel + value.lat + value.lon; 
}); 

その後、カウントを更新し、一つに各グループメンバーを統合:

var data = _.map(groups, function(group){ 
    return { 
     facilities: group.length, 
     place: group[0].place, 
     state: group[0].state, 
     lat: group[0].lat, 
     lon: group[0].lon 
    } 
}); 
0

シンプルでエレガント。必要に応じて、変更やコメントの改善ができます。私はes6のビットを使用します。

var _ = require('underscore'); 

// Check if array arr contains object obj 
function exists(arr, obj) { 
    var found = false; 

    arr.forEach((item) => { 
     if (_.isMatch(item, obj)) { 
      found = true; 
     } 
    }); 

    return found; 
} 

var final = []; 

original.forEach((obj) => { 

    if (exists(final, obj)) { 
     var index = _.findIndex(final, finalObj => _.isMatch(finalObj, obj)) 
     ++final[index].facilities 
    } else { 
     final.push(obj); 
    } 

}); 

return final; 
0

.uniqあなたは文字列に項目を変換する場合は、重複を検出することができるはずコールバック

var list = [ 
     { 
      "facilities": 1, 
      "place": "Campbellsville", 
      "state": "KY", 
      "lat": 37.34595018, 
      "lon": -85.34544564 
     }, 
     { 
      "facilities": 1, 
      "place": "Lexington", 
      "state": "KY", 
      "lat": 38.040584, 
      "lon": -84.503716 
     }, 
     { 
      "facilities": 1, 
      "place": "Hebron", 
      "state": "KY", 
      "lat": 39.066147, 
      "lon": -84.703189 
     }, 
     { 
      "facilities": 1, 
      "place": "Hebron", 
      "state": "KY", 
      "lat": 39.066147, 
      "lon": -84.703189 
     } 
    ] 

var uniqueList = _.uniq(list, function(item) { 
    return item.toString(); 
}); 

/* 
uniqueList will be: 
      { 
       "facilities": 1, 
       "place": "Campbellsville", 
       "state": "KY", 
       "lat": 37.34595018, 
       "lon": -85.34544564 
      }, 
      { 
       "facilities": 1, 
       "place": "Lexington", 
       "state": "KY", 
       "lat": 38.040584, 
       "lon": -84.503716 
      }, 
      { 
       "facilities": 1, 
       "place": "Hebron", 
       "state": "KY", 
       "lat": 39.066147, 
       "lon": -84.703189 
      } 
      */ 

を受け入れます。

注:

  • ユニークunderscorejs.orgとして使用される固有の戻り値との比較
  • まず比較対象のために使用さ

    1. コールバックの戻り値は、コールバックの使用
    2. lodash.comは、使用方法を示していない実証