Самые высокие значения в объекте (больше, если больше значений max и они одинаковы) - PullRequest
1 голос
/ 07 февраля 2020

Предположим, у меня есть такой объект:

var obj = {a : 5, b : 10, c : 15, d : 20, e : 20, f : 25};

Я хотел бы получить 3 самых высоких значения - обратите внимание, что ключи d и e имеют то же значение, и мне нужно также получить ключи, чтобы оно выглядело так:

Максимальные значения:
f - 25
d - 20
e - 20

также, если есть, например, шесть значений и четыре идентичны:

var obj2 = {a:1, b:1, c:1, d:1, e:0,8, f: 0,5};

Мне нужно показать 4 наивысшее.

Наибольшие значения:
a-1
b-1
c -1
d-1

Я предполагаю, что необходимо перебирать ВСЕ свойства объекта, чтобы получить Math.max, но мне также нужно что-то, чтобы посчитать 3 максимальных числа с их ключами, и если есть больше max (все то же самое), мне нужно «получить их все!».

РЕДАКТИРОВАТЬ: там отличные ответы, я думаю, я не буду заканчивать sh этот код и просто буду использовать приведенные примеры:)

Ответы [ 4 ]

2 голосов
/ 07 февраля 2020

Просто,

  1. Сортируйте объект по его значениям, используя, Object.entries
  2. Получите наименьшее значение, которое вы можете отфильтровать.
  3. Отфильтруйте записи и вернитесь как объект, используя Object.fromEntries .

function getTopValues(obj, topN)
{
    var sortedEntries = Object.entries(obj).sort(function(a,b){return b[1]-a[1]});
    var last = sortedEntries[topN-1][1];
    var result = sortedEntries.filter(function(entry){
        return entry[1] >= last;
    });
    console.log(Object.fromEntries(result));
}

getTopValues({a:5, b:10, c:15, d:20, e:20, f:25}, 3);
getTopValues({a:1, b:1, c:1, d:1, e:0.8, f: 0.5}, 3);
getTopValues({a:1, b:1, c:1, d:1, e:0.8, f: 0.5}, 5);
2 голосов
/ 07 февраля 2020

Это пример реализации с аннотациями для объяснения того, что происходит на каждом шаге.

function maxValues(o, n) {
  // Get object values and sort descending
  const values = Object.values(o).sort((a, b) => b - a);
  
  // Check if more values exist than number required
  if (values.length <= n) return o;
  
  // Find nth maximum value
  const maxN = values[n - 1];
  
  // Filter object to return only key/value pairs where value >= maxN
  return Object.entries(o)
    .reduce((o, [k, v]) => v >= maxN ? { ...o, [k]: v } : o, {});
}

const a = maxValues({
  a: 5, 
  b: 10, 
  c: 15, 
  d: 20, 
  e: 20, 
  f: 25
}, 3);
console.log(a);

const b = maxValues({
  a: 1, 
  b: 1, 
  c: 1, 
  d: 1, 
  e: 0.8, 
  f: 0.5
}, 3);
console.log(b);

const c = maxValues({
  a: 5, 
  b: 10,
}, 3);
console.log(c);

Обратный вызов, переданный функции Array.prototype.reduce, может быть расширен до следующего:

return Object.entries(o)
    .reduce(function (obj, [key, value]) {
        if (v >= maxN) {
            return Object.assign(obj, {
                [key]: value
            });
        } else {
            return obj;
        }
    }, {});

Вместо этого я сжал его, используя Выражение функции стрелки , троичный оператор и расширенный синтаксис .

Тернарный оператор по существу является сокращением для оператора if/else. Например,

condition ? true : false;
// or
v >= maxN ? { ...o, [k]: v } : o;

Синтаксис расширения позволяет развернуть итеративное значение на месте. В этом случае он используется для копирования существующих пар key/value из одного литерала объекта в другой.

const a = { first_name: 'Rob', gender: 'male' };
const b = { ...a, username: 'fubar' };

console.log(b); // { first_name: 'Rob', gender: 'male', username: 'fubar' };
1 голос
/ 07 февраля 2020

Я бы начал с преобразования вашего объекта в массив объектов:

const arr = []

for (var key in obj){
  arr.push( {[key]: obj[key]} )
}

Теперь у вас есть массив, который выглядит следующим образом:

[
  {"f": 25},
  {"d": 20},
  {"e": 20},
  {"c": 15},
  {"b": 10},
  {"a": 5}
]

Теперь вы можете сортировать ваши объекты по величине их значений:

const sortedArray = arr.sort( (a,b) => { 
  if (Object.values(a)[0] > Object.values(b)[0]) {
    return -1
  } 
})

Что даст:

[
  {"f": 25},
  {"d": 20},
  {"e": 20},
  {"c": 15},
  {"b": 10},
  {"a": 5}
]

Тогда вы можете просто выбрать столько значений из верхней части, сколько захотите. Например,

sortedArray.filter( (item, index) => {
    if (index <= 2 || Object.values(item)[0] === Object.values(sortedArray[0])[0]) {
      return item
    }
  })

, который дает:

[
  {"f": 25},
  {"d": 20},
  {"e": 20}
]

Или в случае вашего второго объекта он будет соответствовать n наибольшим значениям, но также получит любые другие значения, равные самое высокое значение.

как одна функция:

function sortYourObject(object, number){

  var arr = []

  for (var key in object){
    arr.push( {[key]: object[key]} )
  }

  const sortedArray = arr.sort( (a,b) => { 
    if (Object.values(a)[0] > Object.values(b)[0]) {
      return -1
    } 
  })

  const endresult = sortedArray.filter( (item, index) => {
    if (index <= 2 || Object.values(item)[0] === Object.values(sortedArray[0])[0]) {
      return item
    }
  })

  return endresult

}
1 голос
/ 07 февраля 2020

Итак, вы хотите найти верхнюю тройку самых высоких, и если есть несколько одинаковых высших, вы хотите включить все это.

Эта проблема задается немного странным образом.

Я собираюсь предположить, что если есть что-то вроде a: 1 b: 1 c: 2 d: 2 e: 3, вы хотели бы включить a, b, c и d.

Прежде всего, вам нужно только отслеживать ключи, потому что вы можете получить значения мгновенно в конце.

Хорошо! Давайте начнем. (эффективно, но безобразно)

class Numandamount {
  constructor(number, amount) {
    this.number = number;
    this.amount = amount;
  }
}
//That's just a class to link numbers and their amounts

var numtoamount = [];

//Now let's fill that array!

for (var property in obj) {
  if (obj.hasOwnProperty(property)) {
    var num = obj.property;
    var found = false;
    for(Numandamount naa in numtoamount){
       if(naa.number == num){
           naa.amount++;
           found = true;
       }
    }
    if(!found){
       naa.push(new Numandamount(num,1));
    }
  }
}

//The array is done!

numtoamount.sort(function(a,b){return b.number-a.number});

//Now all we have to do is loop through it!

var count = 0; // keep track of how many we did
var i = 0;
while(count<4 && i<numtoarray.length){
    count += numtoamount[i].amount;
    i++;
}
//BOOOM WE DID IT
// I is the biggest index so all we have to do is:

for(var j = 0;j<i;j++){
   console.log("We have "+numtoamount[j].amount+" "+numtoamount[j].number+"'s");
}

Например. для этого примера он напечатает obj: {a: 1 b: 1 c: 4 d: 6 e: 7 f: 4}

У нас 1 7-е У нас 1 6-е У нас 2 4-х

Если вам нужна другая реализация, пожалуйста, прокомментируйте ниже! Я вложил свое сердце в это <3 </p>

...