【问题标题】:How to find the max values from similar groups in an object如何从对象中的相似组中找到最大值
【发布时间】:2015-05-30 22:50:11
【问题描述】:

我有一个这样的对象

obj = {
 'ab-adf': 2,
 'ab-d': 3,  
 'cd-23': 1,
 'cd-df': 5,
 'ef-a': 3,
 'ef-nb': 4
};

预期的输出数字或字符串:来自每个 ab、cd 和 ef 组的 3、5、4。

我也在寻找像这样 ab-asdf=8, cd-ed=6 等打印出来的解决方案,它应该保留原始名称,后面有一个“=”符号。

我知道最传统的方法是使用循环并返回最大值。

var max = -Infinity, x;
for( x in obj) {
    if( x.slice(0,2)==='ab' && obj[x] > max) max = obj[x];
    if( x.slice(0,2)==='cd' && obj[x] > max) max = obj[x];
    if( x.slice(0,2)==='ef' && obj[x] > max) max = obj[x];
 //how to return max value from each group ?
}

【问题讨论】:

  • 您想返回一个最大值数组吗?
  • 首选数字或字符串
  • 同一个对象中不能有两个同名的键,并且对象的键中不能有减号,除非该键在引号中。我不明白这是怎么可能的。
  • xxx = 不同的值。如此不同的键。是的,很明显,它们应该是引号..
  • 那没问题。

标签: javascript loops object


【解决方案1】:

您可以动态生成max 对象,而无需对组名进行硬编码:

obj = {
 'ab-1': 9,
 'ab-2': 3,  
 'cd-1': 1,
 'cd-2': 5,
 'ef-1': 3,
 'ef-2': 4,
};

max = [], group = null;

Object.keys(obj).sort().forEach(function(key) {
  var g = key.substr(0, 2);
  if(g == group)
    max.push(Math.max(max.pop(), obj[key]));
  else {
    group = g;
    max.push(obj[key]);
  }
});

document.write("<pre>" + JSON.stringify(max))

【讨论】:

  • 感谢您的回答,但是如果我需要获取值 9,5,4,我必须再次使用 for in 循环来获取它们。只是好奇是否有一种方法可以通过只循环一次来获得结果?
【解决方案2】:

首先,JavaScript 将无法解释您的对象,因为键中有特殊字符。您需要将密钥用引号括起来,如下所示:

obj = {
 'ab-xxx': 2,
 'ab-yyy': 3,  
 'cd-xxx': 1,
 'cd-yyy': 6,
 'cd-zzz': 5,
 'ef-xxx': 3,
 'ef-yyy': 4,
};

接下来,您需要存储每个组的最大值,然后连接最大值以获得您要查找的字符串作为输出。

// Get the max values for each prefix
var max = {};
for(var key in obj) {
  var prefix = key.slice(0,2);
  if (max[prefix] === undefined || max[prefix] < obj[key]){
    max[prefix] = obj[key];
  }
}

// Concatenate the max values into a string
var maxString = '';
for(key in max){
  maxString += max[key] + ' ';
}
maxString = maxString.trim();

编辑:

是的,基本上我也在寻找打印出来的解决方案 这个 ab-asdf=8, cd-ed=6 等它应该保留原始名称 '=' 符号。

要实现这个输出,可以这样:

// Get the max values for each prefix, and store the max as a string
var max = {};
for(var key in obj) {
  var prefix = key.slice(0,2);
  if (max[prefix] === undefined || +max[prefix].split('=')[1] < obj[key]){
    max[prefix] = key + '=' + obj[key];
  }
}

// Concatenate the max values into a string
var maxString = '';
for(key in max){
  maxString += max[key] + ', ';
}
maxString = maxString.trim();

【讨论】:

  • 请尝试我的更改。
  • 它只打印同一组的最后一个值,即使第一个值是最大的......
  • 如果您在原始问题中的确切 obj 上对其进行测试,则密钥都是相同的,因此它们将被覆盖。您可以编辑您的示例obj 以包含破坏此解决方案的属性吗?我刚刚尝试了几个不同的键值,但找不到您描述的错误。
  • 你是对的!现在它可以工作了。非常抱歉,非常感谢您的回答。
  • 不客气!如果您对此解决方案感到满意,请将其标记为正确答案。
【解决方案3】:

这将使用第一个对象的最大值创建一个新对象:

var obj = {
  'ab-xxx': 2,
  'ab-yyy': 3,  
  'cd-xxx': 1,
  'cd-yyy': 5,
  'ef-xxx': 3,
  'ef-yyy': 4
},
newobj= {};

for(var i in obj) {
  var key= i.split('-')[0];
  
  newobj[key]= Math.max(newobj[key] || -Infinity, obj[i]);
}

document.body.innerHTML= JSON.stringify(newobj);

你能解释一下 Math.max() 部分吗?

这一行:

newobj[key]= Math.max(newobj[key] || -Infinity, obj[i]);

… 是这个的简写:

if(!newobj[key]) newobj[key]= -Infinity;
newobj[key]= Math.max(newobj[key], obj[i]);

这称为“空值合并”:如果 OR 运算符 (||) 左侧的操作数是 falsy(在本例中为 undefined),则返回右侧的操作数(在本例中为 -Infinity)。

如果Math.max() 的参数之一是undefined,则返回NaN,这样可以防止这种情况发生。


获取最大数量而不是具有新属性名称的新 obj

我非常喜欢@georg 的回答,因为它只循环一次。但这里是如何用我的代码做到这一点:

var obj = {
  'ab-xxx': 2,
  'ab-yyy': 3,  
  'cd-xxx': 1,
  'cd-yyy': 5,
  'ef-xxx': 3,
  'ef-yyy': 4
},
newobj= {};

for(var i in obj) {
  var key= i.split('-')[0];
  
  newobj[key]= Math.max(newobj[key] || -Infinity, obj[i]);
}

var s= [];
Object.keys(newobj).sort().forEach(function(key) {
  s.push(newobj[key]);
});

document.body.innerHTML= s.join(',');

在 JavaScript 中,对象键可以按任何顺序排列,而不管它们是如何定义的。

如果不是这样,那么:

Object.keys(newobj).sort().forEach(function(key) {
  s.push(newobj[key]);
});

……可以大大简化:

for(var key in newobj) {
  s.push(newobj[key]);
});

一种打印原始属性名称及其值的解决方案,如字符串 ab--hello=3, cd-you=2。

Math.max() 在这种情况下无济于事。您需要进行比较,并且需要跟踪键及其值。这是一个解决方案:

var obj = {
  'ab-xxx': 2,
  'ab-hello': 3,  
  'cd-you': 2,
  'cd-zzz': 1,
  'ef-xxx': 3,
  'ef-yyy': 4
},
newobj= {};

for(var i in obj) {
  var txt= i.split('-')[0];
  
  if(!newobj[txt] || (obj[i] > newobj[txt].val)) {
    newobj[txt]= {
      txt: i,
      val: obj[i]
    }
  }
}

var s= [];
Object.keys(newobj).sort().forEach(function(key) {
  s.push(newobj[key].txt+'='+newobj[key].val);
});

document.body.innerHTML= s.join(', ');
  

【讨论】:

  • || 在这里很危险,请考虑ab-xxx: -1, ab-yyy: -2
  • 你能解释一下 Math.max() 部分吗?我知道如何使用 Math.max,但不知道您使用它的方式。如果我能获得最大数量而不是具有新属性名称的新 obj,那就太好了
  • @Rick Hitchcock 太棒了!我现在了解数学部分。我知道你已经回答了我的问题,我非常感谢你的回答。但是,如果您还可以提供一种解决方案来打印原始属性名称及其值,例如字符串 ab--hello=3, cd-you=2,那将是完美的。我也很想知道可能的解决方案。我一直在尝试这样做,但没有运气。
猜你喜欢
  • 1970-01-01
  • 2017-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多