代码之家  ›  专栏  ›  技术社区  ›  brienna

基于多个特性从对象数组中筛选重复项(包括原始值)

  •  0
  • brienna  · 技术社区  · 5 年前

    data 是一个对象列表。我们希望根据多个对象属性过滤掉所有重复项,包括原始值。

    const data = [{
      name: 'x',
      latitude: '45.9',
      longitude: '50.2'
    }, {
      name: 'y',
      latitude: '45.9',
      longitude: '50.2'
    }, {
      name: 'z',
      latitude: '40.5',
      longitude: '85.7'
    }];
    
    const duplicates = data
      .filter((obj, index, array) =>
        array.findIndex(o =>
          o.latitude === obj.latitude &&
          o.longitude === obj.longitude
        ) != index
      );
    
    console.log(duplicates);

    输出:

    [{
      name: 'y',
      latitude: '45.9',
      longitude: '50.2'
    }]
    

    [{
      name: 'x',
      latitude: '45.9',
      longitude: '50.2'
    }, {
      name: 'y',
      latitude: '45.9',
      longitude: '50.2'
    }]
    
    0 回复  |  直到 5 年前
        1
  •  2
  •   Tushar Shahi    5 年前

    而不是 findIndex 还有一个附加条件,即索引不应与您正在检查的索引相同 .

    var data = [
        { name: 'x',
            latitude: '45.9',
          longitude: '50.2'},
        { name: 'y',
            latitude: '45.9',
          longitude: '50.2'},
        { name: 'z',
            latitude: '40.5',
          longitude: '85.7'},
    ];
    
    var duplicates = data.filter((obj, index, array) => {
      for(let i = 0 ; i < array.length;i++){
      if(i!=index && array[i].latitude == obj.latitude 
        && array[i].longitude == obj.longitude ){
          return true;
        }
      }
      return false;    
    });
        
        
    
    console.log(duplicates);
        2
  •  1
  •   Peter Seliger    5 年前

    这 reduce 基于 通过其地理坐标签名检测重复项 它是一个基于字符串的键,由每个项的 latitude 和 longitude 属性值。

    此键用于对坐标项目进行分组,并且组类型的值指示签名是指单个项目还是指相同的坐标项目(重复项)。一旦发现至少有一个双倍物项,这些物项也会被内部蓄能器收集 list 对象因此,这种方法只需迭代一次,并在单个reduce循环结束时提供最终结果。。。

    function collectDuplicates(collector, item) {
      const { index, list } = collector;
      const { latitude, longitude } = item;
    
      const key = [
        parseFloat(latitude),
        parseFloat(longitude),
      ].join('/');
    
      const grouped = index[key];
    
      if (Array.isArray(grouped)) {
        // already more than 2 duplicates detected.
    
        grouped.push(item);
        list.push(item);
    
      } else if (grouped) {
        // first time duplicate detection (2 same items).
    
        index[key] = [grouped, item];
        list.push(grouped, item);
    
      } else {
        // register first item of its kind.
        index[key] = item;
      }
      return collector;
    }
    
    const data = [{
      name: 'x',
      latitude: '45.9',
      longitude: '50.2'
    }, {
      name: 'y',
      latitude: '45.9',
      longitude: '50.2'
    }, {
      name: 'z',
      latitude: '40.5',
      longitude: '85.7'
    }];
    
    const duplicates =
      data.reduce(collectDuplicates, { index: {}, list: [] }).list;
    
    console.log({ duplicates });
    
    console.log(
      'data.reduce(collectDuplicates, { index: {}, list: [] }) ...',
      data.reduce(collectDuplicates, { index: {}, list: [] })
    )
    .as-console-wrapper { min-height: 100%!important; top: 0; }
        3
  •  1
  •   Scott Sauyet    5 年前

    要做到这一点,对代码的简单修复可能如下所示:

    const duplicates = (data) => data
      .filter((obj, index, array) =>
        array.find((o, i) =>
          o.latitude === obj.latitude &&
          o.longitude === obj.longitude &&
          i != index
        ) 
      )
    

    我们只需要测试不匹配的索引 在…内 这个 find

    但我认为,将过滤/dup检查逻辑与测试两个元素是否相等的代码分离开来,可以获得很多好处。分解更符合逻辑,我们从中获得了一个潜在的可重用函数。

    所以我可以这样写:

    const keepDupsBy = (eq) => (xs) => xs .filter (
      (x, i) => xs .find ((y, j) => i !== j && eq (x, y))
    )
    
    const dupLocations = keepDupsBy ((a, b) => 
      a .latitude == b.latitude && 
      a .longitude == b .longitude
    ) 
    
    const data = [{name: 'x', latitude: '45.9', longitude: '50.2'}, {name: 'y', latitude: '45.9', longitude: '50.2'}, {name: 'z', latitude: '40.5', longitude: '85.7'}];
    
    console .log (dupLocations (data))
    .as-console-wrapper {max-height: 100% !important; top: 0}

    这将保留原始数组中在其他位置具有重复项的所有元素,并按原始数组的相对顺序返回它们。这与上面的顺序相同,但不同于Peter Seliger答案中有趣的方法,该方法将所有匹配值分组在一起,并以每组第一个元素的相对顺序返回。

    O (n^2) O (n) . 对于较大的列表,差异可能很大。当涉及到内存资源时,权衡是不同的,正如Peter's在 O(n) 附加内存,而所有其他内存都在恒定内存中运行-- O (1) . 除非你在成千上万的元素或更高的元素中工作,否则这些都不会有什么不同,但这通常是值得考虑的。