使用 Ramda 进行逻辑优化

logical optimisation using Ramda

我使用 Ramda 做了一个解析函数,它像一个 charms 一样工作,但我很确定它可以被简化,不幸的是我正在努力克服这个优化

我想将值分组到一个结构中,该结构具有 'name','y' 是计数。例如,如果 'pending' 出现两次, 'hired' 在我的输入中出现一次,那么我想得到你在输出中看到的内容

我写的函数

const aggResumeStatusTest = data =>
  reduce(
    (acc, elem) => {
      if (!isEmpty(acc)) {
        const indexInArray = findIndex(propEq('name', elem))(acc);
        if (indexInArray !== -1) {
          acc[indexInArray].y++;
        } else {
          acc.push({
            name: elem,
            y: 1,
          });
        }
        return acc;
      }

      acc.push({
        name: elem,
        y: 1,
      });

      return acc;
    },
    [],
    data,
  );

aggResumeStatusTest(['pending', 'pending', 'hired'])

输入

['pending', 'pending', 'hired']

输出

[ { name: 'pending', y: 2 }, { name: 'hired', y: 1 } ]

在此先感谢您的帮助

我不知道这是否算作优化,但您的代码可以简化。

首先,R.groupBy 将所有这些字符串分组。所以你可以从:

['pending', 'pending', 'hired']

收件人:

[['pending', 'pending'], 'hired']

不同之处在于,它 returns 是一个对象,我们只对它的值感兴趣,所以我们使用 R.values

然后你所要做的就是映射它并获取它的长度。

所以最后你有:

let countToObj = arr => ({name : R.head(arr), y: arr.length })
R.map(countToObj, R.values(R.groupBy(R.identity, data)));

let countToObj = arr => ({name : R.head(arr), y: arr.length })
let aggResumeStatusTest = data => R.map(countToObj, R.values(R.groupBy(R.identity, data)));
console.log(aggResumeStatusTest(['pending', 'pending', 'hired']));
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.21.0/ramda.min.js"></script>

使用 ramda 可以轻松完成此任务, 请看一看 R.countBy;

const count = R.pipe(
  R.countBy(R.identity),
  R.toPairs,
  R.map(([name, y]) => ({ name, y })),
)


// ====

const data = ['pending', 'pending', 'hired'];

console.log(
  count(data),
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

我喜欢将这些问题视为一系列转换,并加入 pipecompose

const count = pipe (
  countBy (identity),
  toPairs,
  map (zipObj (['name', 'y']))
)

console .log (count (['pending', 'pending', 'hired']))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
<script> const {pipe, countBy, identity, toPairs, map, zipObj} = R       </script>

这里我们先用countBy转换为{pending: 2, hired: 1}。然后用 toPairs,我们得到 [['pending', 2], ['hired', 1]]。最后,我们mapzipObj将那些数组转换成合适的对象,[{"name": "pending", "y": 2}, {"name": "hired", "y": 1}]

and 的回答非常好,我完全赞同。

我想展示另一种实现方法。首先使用普通 JavaScript,我们可以对 Map 进行计数,然后将该 map 作为可迭代对象 Array.from 转换为对象:

const countBy = (mapping, input) => {
  const m = new Map();
  for (const item of input) {
    const key = mapping(item);
    m.set(key, (m.get(key) ?? 0) + 1);
  }
  return m.entries();
};

const identity = x => x;

const count = input =>
  Array.from(
    countBy(identity, input), 
    ([name, y]) => ({name, y})
  );

console.log(count(['pending', 'pending', 'hired']));
.as-console-wrapper {
  max-height: 100% !important;
}

这可以转换成 Ramda 的说法:

//custom implementation
// (a → b) → [a] → [[b, Number]]
const countBy = curry((mapping, input) => {
  const m = new Map();
  for (const item of input) {
    const key = mapping(item);
    m.set(key, (m.get(key) ?? 0) + 1);
  }
  return m.entries();
});

const arrayFrom = pipe(binary, flip, curry) (Array.from);

const count = pipe (
  countBy(identity),
  arrayFrom(zipObj(["name", "y"]))
);

console.log(count(['pending', 'pending', 'hired']));
.as-console-wrapper {
  max-height: 100% !important;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
<script> const {pipe, curry, identity, flip, zipObj, binary} = R; </script>

有了这个,您不仅可以对字符串进行分组,还可以对任何数据类型进行分组,因为映射将保留放入的任何数据:

//custom implementation
// (a → b) → [a] → [[b, Number]]
const countBy = curry((mapping, input) => {
  const m = new Map();
  for (const item of input) {
    const key = mapping(item);
    m.set(key, (m.get(key) ?? 0) + 1);
  }
  return m.entries();
});

const arrayFrom = pipe(binary, flip, curry) (Array.from);

const count = pipe (
  countBy(identity),
  arrayFrom(zipObj(["name", "y"]))
);

console.log(" --- numbers --- ");
console.log(count([1, 2, "1", 2]));


console.log(" --- objects --- ");
const o1 = {foo: 1};
const o2 = {foo: 2};
const o3 = {foo: 1};
console.log(count([o1, o2, o3, o2]));
.as-console-wrapper {
  max-height: 100% !important;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
<script> const {pipe, curry, identity, flip, zipObj, binary} = R; </script>

同样,这个实现可能是不需要的。但在极少数情况下可能会引起兴趣。