按最小对象值区分对象数组

Distinct array of objects by smallest object value

我有一个对象数组:

    [{Name: "Company 1", AddressName: "Address 1", Radius: "5000" },
    {Name: "Company 1", AddressName: "Address 1", Radius: "2000" },
    {Name: "Company 1", AddressName: "Address 1", Radius: "500" },
    {Name: "Company 2", AddressName: "Address 2", Radius: "500" },
    {Name: "Company 3", AddressName: "Address 3", Radius: "3000" },
    ...]

有些公司可以出现在不同的半径内,所以在阵列中它们会出现多次。

我要的是:如果同名同地址的公司在数组中多次出现,只保留半径最小的公司:

    [{Name: "Company 1", AddressName: "Address 1", Radius: "500" },
    {Name: "Company 2", AddressName: "Address 2", Radius: "500" },
    {Name: "Company 3", AddressName: "Address 3", Radius: "3000" },
    ...]

const arr = [
 {Name: "Company 1", AddressName: "Address 1", Radius: "5000" },
 {Name: "Company 1", AddressName: "Address 1", Radius: "2000" },
 {Name: "Company 1", AddressName: "Address 1", Radius: "500" },
 {Name: "Company 2", AddressName: "Address 2", Radius: "500" },
 {Name: "Company 3", AddressName: "Address 3", Radius: "3000" },
];
const res = arr.sort((a, b) => +a.Radius - +b.Radius)
 .filter((a, i) => arr.findIndex((b) => a.Name === b.Name && a.AddressName === b.AddressName) === i);

console.log(res);

没有提前排序的解决方案。


基本上,您需要按 Name 进行分组,并通过最小化每个组的 Radius 进行额外过滤。

此方法尝试查找同一组的索引,如果找不到index === -1,它会将实际对象推送到结果集中。

否则如果存储对象Radius的数值大于实际对象,则将结果集中的对象替换为实际对象

var data = [{ Name: "Company 1", AddressName: "Address 1", Radius: "5000" }, { Name: "Company 1", AddressName: "Address 1", Radius: "2000" }, { Name: "Company 1", AddressName: "Address 1", Radius: "500" }, { Name: "Company 2", AddressName: "Address 2", Radius: "500" }, { Name: "Company 3", AddressName: "Address 3", Radius: "3000" }],
    result = data.reduce((r, o) => {
        var index = r.findIndex(q => q.Name === o.Name);
        if (index === -1) r.push(o);
        else if (+r[index].Radius > +o.Radius) r[index] = o;
        return r;
    }, []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }


如果你想让它更实用并且松散地基于 SQL,比如下面的查询,

SELECT Name, AddressName, MIN(Radius) 
FROM data 
GROUP BY Name;

您可以先分组,然后从结果集中取出最小对象。

result = pipe(
    groupBy('Name'),
    select(max('Radius'))
)(data);

const
    pipe = (...functions) => input => functions.reduce((acc, fn) => fn(acc), input),
    groupBy = key => array => array.reduce((r, o) => {
        var temp = r.find(([p]) => o[key] === p[key])
        if (temp) temp.push(o);
        else r.push([o]);
        return r;
    }, []),
    min = key => array => array.reduce((a, b) => +a[key] < +b[key] ? a : b),
    select = fn => array => array.map(fn);


var data = [{ Name: "Company 1", AddressName: "Address 1", Radius: "5000" }, { Name: "Company 1", AddressName: "Address 1", Radius: "2000" }, { Name: "Company 1", AddressName: "Address 1", Radius: "500" }, { Name: "Company 2", AddressName: "Address 2", Radius: "500" }, { Name: "Company 3", AddressName: "Address 3", Radius: "3000" }],
    result = pipe(
        groupBy('Name'),
        select(min('Radius'))
    )(data);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

从@ponury-cubes 中汲取灵感,

// this will return object
    var c = test.sort((a,b) => +b.Radius - +a.Radius).reduce((a,d)=>{
      a[`${d.Name}:${d.AddressName}`] =  d;
      return a;
    },{});

// this will convert to array of objects
    var res = Object.keys(c).reduce((a,d)=>{
      a.push(c[`${d}`]);
      return a;
    },[]);