Ramda:在另一个数组中找到一个数组的最低出现次数
Ramda: Find lowest occasions of one array in another array
我有两个包含字符串的数组。第二个数组只能包含第一个但多次出现的字符串。我试图找到第二个数组中出现次数最少的单词。以下是一些示例:
const original = ['foo', 'bar', 'baz'];
const arr1 = ['foo', 'bar']; // => ['baz'] because 'baz' is 0 times in arr1.
const arr2 = ['foo', 'foo', 'bar']; // => ['baz'] because 'baz' is 0 times in arr2.
const arr3 = ['foo', 'foo', 'bar', 'bar', 'baz']; // => ['baz'] because 'baz' in 1 time in arr3.
const arr4 = ['foo', 'bar', 'baz']; // => ['foo', 'bar', 'baz']; because they are all the lowest (1 time).
const arr5 = ['foo', 'foo', 'bar', 'bar', 'bar', 'baz', 'baz']; // => ['foo', 'baz'] because they are both only 2 times in arr5
你会如何用 Ramda 做这个? (或一般在 JS 中)?我觉得它可以用 R.countBy
解决,但我不知道如何获得所有具有最低值的键。
您可以使用R.countBy,但您必须创建一个默认对象,其中originals
中的每个项目的值为0,然后合并它们。然后求最小值,过滤original
数组:
const { chain, flip, zipObj, map, always, curry, pipe, countBy, identity, mergeRight, values } = R;
const getDefaults = chain(flip(zipObj), map(always(0)));
const countWithDefaults = curry((dflts, arr) => pipe(
countBy(identity),
mergeRight(dflts),
)(arr));
const fn = curry((orig, arr) => {
const counts = countWithDefaults(getDefaults(orig), arr);
const min = Math.min(...values(counts));
return original.filter(k => counts[k] === min);
});
const original = ['foo', 'bar', 'baz'];
const fnO = fn(original);
console.log(fnO(['foo', 'bar'])); // => ['baz'] because 'baz' is 0 times in arr1.
console.log(fnO(['foo', 'foo', 'bar'])); // => ['baz'] because 'baz' is 0 times in arr2.
console.log(fnO(['foo', 'foo', 'bar', 'bar', 'baz'])); // => ['baz'] because 'baz' in 1 time in arr3.
console.log(fnO(['foo', 'bar', 'baz'])); // => ['foo', 'bar', 'baz']; because they are all the lowest (1 time).
console.log(fnO(['foo', 'foo', 'bar', 'bar', 'bar', 'baz', 'baz'])); // => ['foo', 'baz'] because they are both only 2 times in arr5
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
纯 ES6 版本还不错:
const minOccurences = (orig, xs) =>
Object .entries (xs .reduce (
(a, x) => ({... a, [x]: (a [x] || 0) + 1}),
Object .assign (... orig .map (x => ({[x]: 0})))
)).reduce(
({vs, m}, [v, c]) => c < m ? {vs: [v], m: c} : c == m ? {vs: [...vs, v], m} : {vs, m},
{vs: [], m: Infinity}
).vs
const original = ['foo', 'bar', 'baz'];
console.log (minOccurences(original, ['foo', 'bar'])); // => ['baz'] because 'baz' is 0 times in arr1.
console.log (minOccurences(original, ['foo', 'foo', 'bar'])); // => ['baz'] because 'baz' is 0 times in arr2.
console.log (minOccurences(original, ['foo', 'foo', 'bar', 'bar', 'baz'])); // => ['baz'] because 'baz' in 1 time in arr3.
console.log (minOccurences(original, ['foo', 'bar', 'baz'])); // => ['foo', 'bar', 'baz']; because they are all the lowest (1 time).
console.log (minOccurences(original, ['foo', 'foo', 'bar', 'bar', 'bar', 'baz', 'baz'])); // => ['foo', 'baz'] because they are both only 2 times in arr5
.as-console-wrapper {min-height: 100% !important; top: 0}
我们首先在 Obect.assign
调用中从原始数组创建一个基本计数对象 {foo: 0, bar: 0, baz: 0}
。我们将其作为初始值输入到第一个 reduce
调用中,将第二个数组折叠成 {foo: 2, bar: 3, baz: 2}
之类的东西。然后我们的第二个 reduce
调用将它折叠成类似 {vs: ['foo', 'baz'], m: 2}
的东西,其中 m
是最小计数,vs
具有该计数的项目。然后我们只需从结果中提取 vs
即可得到答案。
我有两个包含字符串的数组。第二个数组只能包含第一个但多次出现的字符串。我试图找到第二个数组中出现次数最少的单词。以下是一些示例:
const original = ['foo', 'bar', 'baz'];
const arr1 = ['foo', 'bar']; // => ['baz'] because 'baz' is 0 times in arr1.
const arr2 = ['foo', 'foo', 'bar']; // => ['baz'] because 'baz' is 0 times in arr2.
const arr3 = ['foo', 'foo', 'bar', 'bar', 'baz']; // => ['baz'] because 'baz' in 1 time in arr3.
const arr4 = ['foo', 'bar', 'baz']; // => ['foo', 'bar', 'baz']; because they are all the lowest (1 time).
const arr5 = ['foo', 'foo', 'bar', 'bar', 'bar', 'baz', 'baz']; // => ['foo', 'baz'] because they are both only 2 times in arr5
你会如何用 Ramda 做这个? (或一般在 JS 中)?我觉得它可以用 R.countBy
解决,但我不知道如何获得所有具有最低值的键。
您可以使用R.countBy,但您必须创建一个默认对象,其中originals
中的每个项目的值为0,然后合并它们。然后求最小值,过滤original
数组:
const { chain, flip, zipObj, map, always, curry, pipe, countBy, identity, mergeRight, values } = R;
const getDefaults = chain(flip(zipObj), map(always(0)));
const countWithDefaults = curry((dflts, arr) => pipe(
countBy(identity),
mergeRight(dflts),
)(arr));
const fn = curry((orig, arr) => {
const counts = countWithDefaults(getDefaults(orig), arr);
const min = Math.min(...values(counts));
return original.filter(k => counts[k] === min);
});
const original = ['foo', 'bar', 'baz'];
const fnO = fn(original);
console.log(fnO(['foo', 'bar'])); // => ['baz'] because 'baz' is 0 times in arr1.
console.log(fnO(['foo', 'foo', 'bar'])); // => ['baz'] because 'baz' is 0 times in arr2.
console.log(fnO(['foo', 'foo', 'bar', 'bar', 'baz'])); // => ['baz'] because 'baz' in 1 time in arr3.
console.log(fnO(['foo', 'bar', 'baz'])); // => ['foo', 'bar', 'baz']; because they are all the lowest (1 time).
console.log(fnO(['foo', 'foo', 'bar', 'bar', 'bar', 'baz', 'baz'])); // => ['foo', 'baz'] because they are both only 2 times in arr5
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
纯 ES6 版本还不错:
const minOccurences = (orig, xs) =>
Object .entries (xs .reduce (
(a, x) => ({... a, [x]: (a [x] || 0) + 1}),
Object .assign (... orig .map (x => ({[x]: 0})))
)).reduce(
({vs, m}, [v, c]) => c < m ? {vs: [v], m: c} : c == m ? {vs: [...vs, v], m} : {vs, m},
{vs: [], m: Infinity}
).vs
const original = ['foo', 'bar', 'baz'];
console.log (minOccurences(original, ['foo', 'bar'])); // => ['baz'] because 'baz' is 0 times in arr1.
console.log (minOccurences(original, ['foo', 'foo', 'bar'])); // => ['baz'] because 'baz' is 0 times in arr2.
console.log (minOccurences(original, ['foo', 'foo', 'bar', 'bar', 'baz'])); // => ['baz'] because 'baz' in 1 time in arr3.
console.log (minOccurences(original, ['foo', 'bar', 'baz'])); // => ['foo', 'bar', 'baz']; because they are all the lowest (1 time).
console.log (minOccurences(original, ['foo', 'foo', 'bar', 'bar', 'bar', 'baz', 'baz'])); // => ['foo', 'baz'] because they are both only 2 times in arr5
.as-console-wrapper {min-height: 100% !important; top: 0}
我们首先在 Obect.assign
调用中从原始数组创建一个基本计数对象 {foo: 0, bar: 0, baz: 0}
。我们将其作为初始值输入到第一个 reduce
调用中,将第二个数组折叠成 {foo: 2, bar: 3, baz: 2}
之类的东西。然后我们的第二个 reduce
调用将它折叠成类似 {vs: ['foo', 'baz'], m: 2}
的东西,其中 m
是最小计数,vs
具有该计数的项目。然后我们只需从结果中提取 vs
即可得到答案。