【问题标题】:How to skip a duplicate object using a property value within reduce function in javascript?如何使用javascript中reduce函数中的属性值跳过重复对象?
【发布时间】:2019-10-04 14:40:59
【问题描述】:

我有一个这样的对象数组:

// other properties of the object omitted for brevity
// this array can potentially contain upto 50 objects like this
var myArray = [{url: 'http://linkA'}, {url: 'http://linkB'}, {url: 'http://linkA'}]

我正在尝试应用 reduce 函数来创建一个像这样的新对象:

  var newArray = myArray.reduce(function(acc, current, index){
  var newObj = {};
  newObj['strata']  = 'kit';
  newObj['href'] = current['url'];
  acc.push(newObj);
  return acc;  
}, [])

但我不想包含重复的对象(使用对象的 'url' 属性测试的'duplicate')。如何修改我的 reduce 函数以跳过这些类型的对象并生成一个

[{strata: kit, href: 'http://linkA'}, {strata: kit, href: 'http://linkB'}]

编辑:抱歉,我忘了说这是遗留代码。我无法使用“设置”和“某些”等功能

【问题讨论】:

  • 预期输出是什么?
  • 请看编辑
  • 请注意,当您无条件地推送到一个新数组时,您已作为 reduce 中的累加器传入(如上),您使用了错误的工具;请改用map。 (但如果是有条件的,map 就不合适了,最好使用简单的循环。)

标签: javascript arrays object duplicates


【解决方案1】:

你可以先检查url是否存在于累加器中的任何对象中:

var myArray = [{
  url: 'http://linkA'
}, {
  url: 'http://linkB'
}, {
  url: 'http://linkA'
}];

var newArray = myArray.reduce(function(acc, { url }, index) {
  if (acc.some(obj => obj.href === url)) {
    return acc;
  }
  acc.push({
    strata: 'kit',
    href: url
  });
  return acc;
}, [])

console.log(newArray);

对于O(N) 复杂性而不是O(N^2),将每个URL 添加到外部Set(其查找是O(1),而不是O(N) 用于Array.prototype.some):

var myArray = [{
  url: 'http://linkA'
}, {
  url: 'http://linkB'
}, {
  url: 'http://linkA'
}];

const urls = new Set();
var newArray = myArray.reduce(function(acc, { url }, index) {
  if (urls.has(url)) {
    return acc;
  }
  urls.add(url);
  acc.push({
    strata: 'kit',
    href: url
  });
  return acc;
}, [])

console.log(newArray);

或者,在 ES5 中,使用对象而不是 Set:

var myArray = [{
  url: 'http://linkA'
}, {
  url: 'http://linkB'
}, {
  url: 'http://linkA'
}];

var urls = {};
var newArray = myArray.reduce(function(acc, obj, index) {
  var url = obj.url;
  if (urls[url]) {
    return acc;
  }
  urls[url] = true;
  acc.push({
    strata: 'kit',
    href: url
  });
  return acc;
}, [])

console.log(newArray);

【讨论】:

  • 我能问一下为什么使用Object.values(acc).some而不是acc.some吗?
  • 糟糕,它已经是一个数组了,你是对的。我已经习惯了.reduce 的累加器,当不是原始的时候,是一个对象
  • 您能否建议我如何替换 acc.some,因为这是旧代码?
  • @Adhyatmik 最好使用 Babel 和 polyfills,这样您就可以使用该语言的最新和最好的版本进行编写 - 但如果不是,请参阅编辑,使用对象而不是 Set,例如底部sn-p
  • 应该是:if (urls[url]) { } ?
【解决方案2】:

使用some:

var myArray = [{url: 'http://linkA'}, {url: 'http://linkB'}, {url: 'http://linkA'}];

var newArray = myArray.reduce(function(acc, { url }, index) {
  if (Object.values(acc).some(({ href }) => href === url)) {
    return acc;
  }
  acc.push({
    strata: 'kit',
    href: url
  });
  return acc;
}, [])

console.log(newArray);

【讨论】:

    【解决方案3】:

    您可以在push() 之前使用some() 检查重复项

    var myArray = [{url: 'http://linkA'}, {url: 'http://linkB'}, {url: 'http://linkA'}]
    
    var newArray = myArray.reduce(function(acc, current, index){
      var newObj = {};
      newObj['strata']  = 'kit';
      newObj['href'] = current['url'];
      if(!acc.some(x => x.href === current.url)) acc.push(newObj);
      return acc;  
    }, [])
    
    console.log(newArray)

    更短的代码版本将是

    var myArray = [{url: 'http://linkA'}, {url: 'http://linkB'}, {url: 'http://linkA'}]
    
    const res=  myArray.reduce((ac,a) => 
                      (!ac.some(x => x.href === a.url) && 
                      ac.push({strata:'kit',href:a.url}),
                      ac),
                 []);
    
    console.log(res)

    【讨论】:

      【解决方案4】:

      您可以先使用Set 获得所有唯一的urls。然后使用mapShorthand property names 创建对象:

      const myArray = [{url: 'http://linkA'}, {url: 'http://linkB'}, {url: 'http://linkA'}],
            uniqueUrls = new Set(myArray.map(a => a.url)),
            strata = "kit",
            output = [...uniqueUrls].map(href => ({ strata, href }));
      
      console.log(output)

      如果你不能使用 ES2015+ 的特性,你可以有一个对象作为累加器,每个唯一的 url 作为键。这样,您将在累加器中仅获得一个 url。然后循环遍历对象,得到合并对象的值

      var myArray = [{url: 'http://linkA'}, {url: 'http://linkB'}, {url: 'http://linkA'}];
      
      var merged = myArray.reduce(function(acc, current) {
        acc[current.url] = current;
        return acc;
      }, {})
      
      var output = [];
      
      for(var key in merged) {
        output.push(merged[key])
      }
      
      console.log(output)

      这是合并后的对象的样子:

      {
        "http://linkA": {
          "url": "http://linkA"
        },
        "http://linkB": {
          "url": "http://linkB"
        }
      }
      

      【讨论】:

        【解决方案5】:

        我可能会

        • 使用Set(或对象)来跟踪我已经看到的网址,并且
        • 使用对象初始化器而不是三个语句来创建新对象,并且
        • 使用简单的循环而不是reduce

        但这里有一个版本仍在使用reduce

        var myArray = [{url: 'http://linkA'}, {url: 'http://linkB'}, {url: 'http://linkA'}]
        var known = new Set();
        var newArray = myArray.reduce(function(acc, current, index){
          if (!known.has(current.url)) {
            acc.push({
              strata: 'kit',
              href: current.url
            });
            known.add(current.url);
          }
          return acc;  
        }, [])
        console.log(newArray);

        这是我认为使用循环的更简单的版本:

        var myArray = [{url: 'http://linkA'}, {url: 'http://linkB'}, {url: 'http://linkA'}]
        var known = new Set();
        var newArray = [];
        for (const current of myArray) {
          if (!known.has(current.url)) {
            newArray.push({
              strata: 'kit',
              href: current.url
            });
            known.add(current.url);
          }
        }
        console.log(newArray);

        如果您不能使用 ES2015+ 功能,例如 Setfor-of,您可以使用一个对象来跟踪 URL 和一个简单的 for 循环:

        var myArray = [{url: 'http://linkA'}, {url: 'http://linkB'}, {url: 'http://linkA'}]
        var known = Object.create(null); // An object with no prototype
        var newArray = [];
        for (var index = 0; index < myArray.length; ++index) {
          var current = myArray[index];
          if (!known[current.url]) {
            newArray.push({
              strata: 'kit',
              href: current.url
            });
            known[current.url] = true;
          }
        }
        console.log(newArray);

        【讨论】:

        • 对不起,我忘了提。这是 ECMAScript 6 之前的遗留代码。我不认为 Set 和一些会工作。
        • @Adhyatmik - 啊,然后看看我刚才添加的 ES5 解决方案。 :-)
        【解决方案6】:

        创建一个Set,它接受您的数组的映射版本,其中仅包含 url - Set 将对您的数组进行重复数据删除,然后您可以从 Set 中创建一个新数组,并添加 strata 属性.

        const myArray = [{url: 'http://linkA'}, {url: 'http://linkB'}, {url: 'http://linkA'}]
        const s = new Set(myArray.map(({ url }) => url))
        
        const newArray = [...s].map(url => ({
          url,
          strata: 'kit'
        }))
        console.log(newArray)

        如果您希望最终的对象数组更加动态。创建一个函数,该函数接受您要进行重复数据删除的参数以及您要插入到最终对象中的参数。

        const DE_DUPE_INSERT = (array, flag, insert) => {
          const s = new Set(array.map(item => item[flag]))
          return [...s].map(property => ({
            [flag]: property,
            ...insert
          }))
        }
        const ARR = [{url: 'http://linkA'}, {url: 'http://linkB'}, {url: 'http://linkA'}]
        const de_duped = DE_DUPE_INSERT(ARR, 'url', {strata: 'kit', foo: 'bar'})
        
        console.log(de_duped)

        &lt; es6

        var DE_DUPE_INSERT = function (array, flag, insert) {
          var de_duped = []
          array.forEach(function (item) {
            if (de_duped.indexOf(item[flag]) === -1) de_duped.push(item[flag])
          })
          
          return de_duped.map(function (property) { 
            var obj = {}
            obj[flag] = property
            Object.keys(insert).forEach(function (key) {
              obj[key] = insert[key]
            })
            return obj
          })
        }
        var ARR = [{url: 'http://linkA'}, {url: 'http://linkB'}, {url: 'http://linkA'}]
        var de_duped = DE_DUPE_INSERT(ARR, 'url', {strata: 'kit', foo: 'bar'})
        
        console.log(de_duped)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-12-07
          • 1970-01-01
          • 1970-01-01
          • 2023-01-03
          • 1970-01-01
          • 2015-04-25
          相关资源
          最近更新 更多