从匹配的数组中获取嵌套数组的名称

3

我有一些数组,如果它们包含相似的值,我想返回这些数组的名称。

    var x = {
      "food": ['bacon', 'cheese', 'bread', 'tomato'],
      "utilities": ['plates', 'forks', 'spatulas'],
      "guests": ['john', 'matt', 'bill']
    },
    y = ['bacon', 'tomato', 'forks'];

我的变量x中有多个数组,它们的名称可以是foodutilitiesguests。变量y只包含在x的某些数组中相同的值。我需要返回包含bacontomatoforks的数组的名称。所以对于这个例子,我需要返回:["food", "utilities"]

    function getContainerName(obj, values) {
      return Object.keys(obj).find(function(key) {
        return values.every(value => obj[key].find(function(elem) {
          return elem === value;
        }));
      });
    }
    console.log(getContainerName(x, y));

运行此函数时,我遇到了一个错误*********。如何获取一个返回["food", "utilities"]的数组呢?

3个回答

4
一个简单的reduce()函数应用于Object.keys即可完成任务。

var x = {
    "food": ['bacon', 'cheese', 'bread', 'tomato'],
    "utilities": ['plates', 'forks', 'spatulas'],
    "guests": ['john', 'matt', 'bill']
  },
  y = ['bacon', 'tomato', 'forks'];

let res = Object.keys(x).reduce((a, b) => {
  if (x[b].some(v => y.includes(v))) a.push(b);
  return a;
}, []);

console.log(res);

针对您的评论 - 使用 var 和普通函数:

var res = Object.keys(x).reduce(function (a, b) {
    if (x[b].some(function (v) {
            return y.indexOf(v) !== -1;
        })) a.push(b);
    return a;
}, []);

很好的想法@tymeJV,但是由于对象键在定义上是唯一的,并且有些会在第一个命中处停止,我不认为可能会出现重复。你能说出可能发生这种情况的场景吗? - baao
1
啊,是的,算了吧 - 它正在循环键。只有在你先循环 y 的情况下才会发生这种情况 - 算了 :) - tymeJV
非常好用,我以前没用过 let,我可以轻松地用 function() 替换它吗? - Ackados
1
@Ackados let是代替var的一个新关键字,如果您打算在现代浏览器中使用它或者使用转译器,那么可以将其替换。不过,箭头函数也可以用function()来替换。我编辑了答案,使用了普通函数和var - baao
1
不错的方法,使用.reduce() - cнŝdk
显示剩余2条评论

3
你可以使用 y 数组的映射和 Array#some 方法来 Array#filter 数组 Object#keys

var x = {
  "food": ['bacon', 'cheese', 'bread', 'tomato'],
  "utilities": ['plates', 'forks', 'spatulas'],
  "guests": ['john', 'matt', 'bill']
};
var y = ['bacon', 'tomato', 'forks'];
var yMap = y.reduce(function(o, v) { // create a map to save iteration of y on each comparsion
  o[v] = true;

  return o;
}, {});

var result = Object.keys(x).filter(function(key) { // filter the keys
  return x[key].some(function(v) { // keep the key, if at least one item of the array is in the map
    return yMap[v];
  });
});

console.log(result);

而使用ES6版本的Set

const x = {
  "food": ['bacon', 'cheese', 'bread', 'tomato'],
  "utilities": ['plates', 'forks', 'spatulas'],
  "guests": ['john', 'matt', 'bill']
};
const y = ['bacon', 'tomato', 'forks'];
const ySet = new Set(y);

const result = Object.keys(x).filter((key) => x[key].some((item) => ySet.has(item)));

console.log(result);


1
您可以使用Object.keys()方法和 .filter() 以及 .some() 方法来实现此功能:
function getContainerName(obj, values) {
  return Object.keys(obj).filter(function(key) {
    return y.some(function(v){
      return obj[key].indexOf(v) !== -1;
    })
  });
}

演示:

var x = {
    "food": ['bacon', 'cheese', 'bread', 'tomato'],
    "utilities": ['plates', 'forks', 'spatulas'],
    "guests": ['john', 'matt', 'bill']
  },
  y = ['bacon', 'tomato', 'forks'];


function getContainerName(obj, values) {
  return Object.keys(obj).filter(function(key) {
    return y.some(function(v){
      return obj[key].indexOf(v) !== -1;
    })
  });
}
console.log(getContainerName(x, y));


如果我正确添加了代码,这个可以导致更快的速度。https://jsperf.com/faster-array-naming - Ackados
@Ackados 我认为这是因为这个方案的指令比其他方案少,但它们只是解决问题的不同方式,选择其中一种取决于情况,以及你是否担心性能可读性 - cнŝdk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接