基于 Array#reduce 如何识别与某些特定约束最匹配的数组项?

Based on Array#reduce how does one identify the array item which matches best some specific constraints?

基本上我要做的是映射这个数组并确定哪些对象满足特定条件。条件是: 获取一个具有最高 a+b 值的对象,如果您有两个具有相同 a+b 值的对象,则获取具有最高 c 值的对象。做这个的最好方式是什么?也许减少?

   const data = [
      {
        id: 1,
        a: 12,
        b: 75,
        c: 11,
      },
      {
        id: 2,
        a: 65,
        b: 14,
        c: 32,
      },
      {
        id: 3,
        a: 32,
        b: 23,
        c: 45,
      },
      {
        id: 4,
        a: 22,
        b: 1,
        c: 3,
      },
    ];

一个简单的 for 循环应该可以工作。遍历数组,如果当前对象的 a + b 大于存储的对象,则用当前循环对象覆盖存储的对象 - 如有必要,检查 c

第一个基于 reduce 的朴素方法实现了 OP 的要求和约束,几乎完全符合 OP 的要求。

如果不向 reducer 提供 initial value,则此缩减回调函数会在第一次调用时传递前两个数组项。该函数应该 return 一个值,在接下来的任何迭代步骤中,该值将作为函数的第一个参数与当前处理的数组项(即第二个参数)一起传递。

因此,对于 OP 的用例,只需实施正确的比较,始终确保预期的 return 值 ...

function getItemWithHighestTotal(result, item) {
  const resultTotal = result.a + result.b;
  const itemTotal = item.a + item.b;
  return (
    ((resultTotal > itemTotal) && result) ||
    ((resultTotal < itemTotal) && item) ||
    ((result.c < item.c) && item) ||
    // OP did not define the clause where
    // even both `c` values are equal.
    result
  );
}

console.log(
  [{
    id: 1,
    a: 12,
    b: 75,
    c: 11,
  }, {
    id: 2,
    a: 65,
    b: 14,
    c: 32,
  }, {
    id: 3,
    a: 32,
    b: 23,
    c: 45,
  }, {
    id: 4,
    a: 22,
    b: 1,
    c: 3,
  }].reduce(getItemWithHighestTotal)
);
console.log(
  [{
    id: 1,
    a: 12,
    b: 75,
    c: 11,
  }, {
    id: 2,
    a: 65,
    b: 14,
    c: 32,
  }, {
    id: 3,
    a: 32,
    b: 23,
    c: 45,
  }, {
    id: 4,
    a: 22,
    b: 1,
    c: 3,
  }, {
    id: 5,
    a: 75,
    b: 12,
    c: 12,
  }].reduce(getItemWithHighestTotal)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

一个简单的 for 循环会很棒

const data = [
      {
        id: 1,
        a: 12,
        b: 75,
        c: 11,
      },
      {
        id: 2,
        a: 65,
        b: 14,
        c: 32,
      },
      {
        id: 3,
        a: 32,
        b: 23,
        c: 45,
      },
      {
        id: 4,
        a: 22,
        b: 1,
        c: 3,
      },
    ];
    
let index,
  cHigh = Number.MIN_SAFE_INTEGER,
  total = Number.MIN_SAFE_INTEGER;

for (let i = 0; i < data.length; ++i) {
  const { a, b, c } = data[i];
  if (a + b > total) {
    total = a + b;
    index = i;
  } else if (a + b === total) {
    if (c > cHigh) {
      cHigh = c;
      index = i;
    }
  }
}
console.log(index);
console.log(data[index]);

data.reduce((res, obj) => {
  if (!res) return obj

  const { a: resA, b: resB, c: resC } = res
  const { a, b, c } = obj

  const sumRes = resA + resB
  const sum = a + b
  
  if(sum > sumRes) return obj
  else if (sum === sumRes) return c > resC ? obj : res
  else return res

}, null)

我觉得很好理解。

我们用第一个索引初始化第一个结果。并且我们做了一个简单的比较游戏

如果您愿意,可以使用 Array#reduce

下面acc累加器用来存放当前已知的最大项。 data 中的每个项目都被访问一次,因此时间复杂度为 O(n)

如果当前项目curra + b值与acc中项目的a + b值相同,那么我们比较两者的c值项目,return 具有较大 c 的项目。

如果当前项的a + b值大于acc中的值,那么我们returncurracc下一个要枚举的项目。

否则我们returnacc(因为curr一定小于acc)。

一旦 data 中的项目枚举完成,reduce 将 return acc 的最终值,这将是“最大”的对象。

const data = [
      { id:1, a:12, b:75, c: 11 },
      { id:2, a:65, b:14, c: 32 },
      { id:3, a:32, b:23, c: 45 },
      { id:4, a:22, b:1,  c: 3  } ]

const largest = (arr) => 
    arr.reduce((acc, curr) => {
        switch(Math.sign((curr.a + curr.b) - (acc.a + acc.b))) {
            case 0:
                return curr.c > acc.c ? curr : acc
            case 1:
                return curr
            default:
                return acc
        }})

       
console.log(largest(data))