Подтвердить что ты не робот

Сравнение JavaScript-массива объектов для получения минимального/максимального значения

У меня есть массив объектов, и я хочу сравнить эти объекты с конкретным свойством объекта. Здесь мой массив:

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

Я хотел бы указать значение "стоимость" в нуль и получить минимальное и максимальное значение. Я понимаю, что могу просто взять значения стоимости и оттолкнуть их в массив javascript, а затем запустить Fast JavaScript Max/Min.

Однако существует ли более простой способ сделать это, минуя шаг массива посередине и непосредственно отключая свойства объектов (в данном случае "Стоимость" )?

4b9b3361

Ответ 1

Самый быстрый способ, в данном случае, перебирать все элементы и сравнивать его с самым высоким/самым низким значением.

(Создание массива, вызов методов массива является излишним для этой простой операции).

 // There 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);

Ответ 2

Редакция полезна для таких вещей: для выполнения агрегатных операций (например, 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.length && this.reduce(function(prev, curr){ 
        return prev[attrib] < curr[attrib] ? prev : curr; 
    })) || null;
 }

Теперь вы можете просто сказать:

myArray.hasMin('ID')  // result:  {"ID": 1, "Cost": 200}
myArray.hasMin('Cost')    // result: {"ID": 3, "Cost": 50}
myEmptyArray.hasMin('ID')   // result: null

Обратите внимание, что если вы собираетесь использовать это, он не имеет полных проверок для каждой ситуации. Если вы передадите массив примитивных типов, он потерпит неудачу. Если вы проверите для свойства, которое не существует, или если не все объекты содержат это свойство, вы получите последний элемент. Эта версия немного более громоздкая, но имеет следующие проверки:

Array.prototype.hasMin = function(attrib) {
    const checker = (o, i) => typeof(o) === 'object' && o[i]
    return (this.length && this.reduce(function(prev, curr){
        const prevOk = checker(prev, attrib);
        const currOk = checker(curr, attrib);
        if (!prevOk && !currOk) return {};
        if (!prevOk) return curr;
        if (!currOk) return prev;
        return prev[attrib] < curr[attrib] ? prev : curr; 
    })) || null;
 }

Ответ 3

Используйте sort, если вам не нужен модифицируемый массив.

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

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

Ответ 4

Я думаю, что ответ 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; }));

Они могут быть легко включены в более полезные/конкретные формы.

Ответ 5

Используйте функции 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

UPDATE:

Если вы хотите использовать ES6:

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

Ответ 6

Это более эффективное решение

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

Ответ 7

Используя Array.prototype.reduce(), вы можете подключить функции компаратора для определения элемента min, max и т.д. в массиве.

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;

Ответ 8

Добавив ответ 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);

Ответ 9

Это может быть достигнуто с помощью функций lodash minBy и maxBy.

Документация по Lodash minBy и maxBy

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

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

Эти методы принимают итерируемого, который вызывается для каждого элемента в массив для генерации критерия, по которому оценивается значение. iteratee вызывается с одним аргументом: (значение).

Решение

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>

Ответ 10

var low = Math.min.apply(Math, myArray.map(function(o) { return o.Cost; }))

Ответ 11

Другой, похожий на ответ Кеннебека, но все в одной строке:

maxsort = myArray.slice(0).sort(function (a, b) { return b.ID - a.ID })[0].ID; 

Ответ 12

Вы можете использовать встроенный объект Array для использования Math.max/Math.min вместо:

var arr = [1,4,2,6,88,22,344];

var max = Math.max.apply(Math, arr);// return 344
var min = Math.min.apply(Math, arr);// return 1