web-dev-qa-db-ja.com

オブジェクトのJavaScript配列を比較して最小/最大を取得

オブジェクトの配列があり、特定のオブジェクトプロパティでそれらのオブジェクトを比較したい。これが私の配列です:

var myArray = [
    {"ID": 1, "Cost": 200},
    {"ID": 2, "Cost": 1000},
    {"ID": 3, "Cost": 50},
    {"ID": 4, "Cost": 500}
]

具体的には「コスト」をゼロにし、最小値と最大値を取得したいと思います。コスト値を取得し、それらをjavascript配列にプッシュしてから、 Fast JavaScript Max/Min を実行できることを理解しています。

ただし、中央の配列ステップをバイパスし、オブジェクトのプロパティ(この場合は「コスト」)を直接オフにすることにより、これを行う簡単な方法はありますか?

74
firedrawndagger

この場合の最速の方法は、すべての要素をループして、これまでの最高値/最低値と比較することです。

(この単純な操作では、配列の作成、配列メソッドの呼び出しはやりすぎです)

 // There's no real number bigger than plus Infinity
var lowest = Number.POSITIVE_INFINITY;
var highest = Number.NEGATIVE_INFINITY;
var tmp;
for (var i=myArray.length-1; i>=0; i--) {
    tmp = myArray[i].Cost;
    if (tmp < lowest) lowest = tmp;
    if (tmp > highest) highest = tmp;
}
console.log(highest, lowest);
47
Rob W

Reduceは次のようなものに適しています:オブジェクトの配列に対して集約操作(min、max、avgなど)を実行し、単一の結果を返す:

myArray.reduce(function(prev, curr) {
    return prev.Cost < curr.Cost ? prev : curr;
});

...またはその内部関数をES6関数構文で定義できます:

(prev, curr) => prev.Cost < curr.Cost ? prev : curr

キュートになりたい場合は、これを配列にアタッチできます。

Array.prototype.hasMin = function(attrib) {
    return this.reduce(function(prev, curr){ 
        return prev[attrib] < curr[attrib] ? prev : curr; 
    });
 }

今、あなたは言うことができます:

myArray.hasMin('ID')  // result:  {"ID": 1, "Cost": 200}
myArray.hasMin('Cost')    // result: {"ID": 3, "Cost": 50}
125
Tristan Reid

配列の変更を気にしない場合は、 sort を使用します。

myArray.sort(function (a, b) {
    return a.Cost - b.Cost
})

var min = myArray[0],
    max = myArray[myArray.length - 1]
21
katspaugh

Rob Wの答え は本当に正しいもの(+1)ですが、ただの楽しみのために:あなたが「賢い」になりたいなら、あなたはできますこのようなことをしてください:

var myArray = 
[
    {"ID": 1, "Cost": 200},
    {"ID": 2, "Cost": 1000},
    {"ID": 3, "Cost": 50},
    {"ID": 4, "Cost": 500}
]

function Finder(cmp, arr, attr) {
    var val = arr[0][attr];
    for(var i=1;i<arr.length;i++) {
        val = cmp(val, arr[i][attr])
    }
    return val;
}

alert(Finder(Math.max, myArray, "Cost"));
alert(Finder(Math.min, myArray, "Cost"));

または、深くネストされた構造がある場合は、もう少し機能的になり、以下を実行できます。

var myArray = 
[
    {"ID": 1, "Cost": { "Wholesale":200, Retail: 250 }},
    {"ID": 2, "Cost": { "Wholesale":1000, Retail: 1010 }},
    {"ID": 3, "Cost": { "Wholesale":50, Retail: 300 }},
    {"ID": 4, "Cost": { "Wholesale":500, Retail: 1050 }}
]

function Finder(cmp, arr, getter) {
    var val = getter(arr[0]);
    for(var i=1;i<arr.length;i++) {
        val = cmp(val, getter(arr[i]))
    }
    return val;
}

alert(Finder(Math.max, myArray, function(x) { return x.Cost.Wholesale; }));
alert(Finder(Math.min, myArray, function(x) { return x.Cost.Retail; }));

これらは、より便利な/特定の形式に簡単にカリー化できます。

13
J. Holmes

Math関数を使用し、mapで必要な値を取り出します。

Jsbinは次のとおりです。

https://jsbin.com/necosu/1/edit?js,console

var myArray = [{
    "ID": 1,
    "Cost": 200
  }, {
    "ID": 2,
    "Cost": 1000
  }, {
    "ID": 3,
    "Cost": 50
  }, {
    "ID": 4,
    "Cost": 500
  }],

  min = Math.min.apply(null, myArray.map(function(item) {
    return item.Cost;
  })),
  max = Math.max.apply(null, myArray.map(function(item) {
    return item.Cost;
  }));

console.log('min', min);//50
console.log('max', max);//1000

更新:

ES6を使用する場合:

var min = Math.min.apply(null, myArray.map(item => item.Cost)),
    max = Math.max.apply(null, myArray.map(item => item.Cost));
11
Rupert

Array.prototype.reduce() を使用すると、コンパレータ関数をプラグインして、配列内の最小、最大などの項目を決定できます。

var items = [
  { name : 'Apple',  count : 3  },
  { name : 'Banana', count : 10 },
  { name : 'Orange', count : 2  },
  { name : 'Mango',  count : 8  }
];

function findBy(arr, key, comparatorFn) {
  return arr.reduce(function(prev, curr, index, arr) { 
    return comparatorFn.call(arr, prev[key], curr[key]) ? prev : curr; 
  });
}

function minComp(prev, curr) {
  return prev < curr;
}

function maxComp(prev, curr) {
  return prev > curr;
}

document.body.innerHTML  = 'Min: ' + findBy(items, 'count', minComp).name + '<br />';
document.body.innerHTML += 'Max: ' + findBy(items, 'count', maxComp).name;
2
Mr. Polywhirl

これはより良い解決策です

    var myArray = [
    {"ID": 1, "Cost": 200},
    {"ID": 2, "Cost": 1000},
    {"ID": 3, "Cost": 50},
    {"ID": 4, "Cost": 500}
    ]
    var lowestNumber = myArray[0].Cost;
    var highestNumber = myArray[0].Cost;

    myArray.forEach(function (keyValue, index, myArray) {
      if(index > 0) {
        if(keyValue.Cost < lowestNumber){
          lowestNumber = keyValue.Cost;
        }
        if(keyValue.Cost > highestNumber) {
          highestNumber = keyValue.Cost;
        }
      }
    });
    console.log('lowest number' , lowestNumber);
    console.log('highest Number' , highestNumber);
2
Deepak Sisodiya

Tristan Reidの答え(es6を使用して+)に追加すると、コールバックを受け入れる関数を作成できます。これには、prevおよびcurrに適用する演算子が含まれます。

const compare = (arr, key, callback) => arr.reduce((prev, curr) =>
    (callback(prev[key], curr[key]) ? prev : curr), {})[key];

    // remove `[key]` to return the whole object

次に、単に次を使用して呼び出すことができます。

const costMin = compare(myArray, 'Cost', (a, b) => a < b);
const costMax = compare(myArray, 'Cost', (a, b) => a > b);
2
James Moran

これは、lodashのminByおよびmaxBy関数で実現できます。

LodashのminByおよびmaxByドキュメント

_.minBy(array, [iteratee=_.identity])

_.maxBy(array, [iteratee=_.identity])

これらのメソッドは、配列内の各要素に対して呼び出されるiterateeを受け入れ、値がランク付けされる基準を生成します。反復子は、1つの引数(値)で呼び出されます。

解決

var myArray = [
    {"ID": 1, "Cost": 200},
    {"ID": 2, "Cost": 1000},
    {"ID": 3, "Cost": 50},
    {"ID": 4, "Cost": 500}
]

const minimumCostItem = _.minBy(myArray, "Cost");

console.log("Minimum cost item: ", minimumCostItem);

// Getting the maximum using a functional iteratee
const maximumCostItem = _.maxBy(myArray, function(entry) {
  return entry["Cost"];
});

console.log("Maximum cost item: ", maximumCostItem);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
0
Trent