【问题标题】:Filter each inner property arrays with Ramda使用 Ramda 过滤每个内部属性数组
【发布时间】:2021-10-11 21:38:49
【问题描述】:

我有一个这样的对象:

const arrays = {
  one: [[1, 33, 41], [2, 0, 27], [3, 7, 9], [4, 1, 3]],
  two: [[1, 77, 2], [2, 6, 3], [3, 0, 0], [4, 55, 3]],
  three: [[1, 4, 6], [2, 0, 0], [3, 5, 6], [4, 0, 0]],
};

如您所见,每个第一个数字都是相等的:
1 代表每个第一个 内部数组
2每秒内部数组
3 代表每三个内部数组
等等……

我想根据每个数组的第一个数字过滤 和一些比较器编号,例如[3]
如果我们有一个过滤器编号 [3](小于或等于 3), 想要的结果是:

const arrays = {
  one:   [[1,33,41], [2,0,27], [3,7,9]],
  two:   [[1,77,2],  [2,6,3],  [3,0,0]],
  three: [[1,4,6],   [2,0,0],  [3,5,6]],
};

由于内部数组的所有第一个数字都小于或等于3。 以 4,5... 开头的数组将被忽略。

ramda 以什么方式拥有此功能?

【问题讨论】:

    标签: javascript arrays functional-programming ramda.js


    【解决方案1】:

    我了解您想使用 Ramda,这不是使用该库的解决方案,但可以实现相同的目的。您可以通过将第一个数组值a[0] 与传递给函数的maxVal 进行比较来创建一个对象from entries,它是filtered

    const arrays = {
      one: [[1, 33, 41], [2, 0, 27], [3, 7, 9], [4, 1, 3]],
      two: [[1, 77, 2], [2, 6, 3], [3, 0, 0], [4, 55, 3]],
      three: [[1, 4, 6], [2, 0, 0], [3, 5, 6], [4, 0, 0]],
    };
    
    const filterArrays = (arsObj, maxVal) => {
      return Object.fromEntries(Object.entries(arsObj).map(([k, v]) => {
        return [k, v.filter((a) => a[0] <= maxVal)];
      }));
    }
    
    const result = filterArrays(arrays, 3);
    console.log(result);

    【讨论】:

    • 谢谢@axtck,只是我们尝试“强制”Ramda。它有助于进一步利用编程的功能方法。我有点喜欢它,但有时它会更耗时。
    【解决方案2】:

    我喜欢 Ramda 的 map 函数,因为它可以迭代对象的属性(因此避免了 Object.fromEntriesObject.entries)并将函数应用于每个对象。该函数是filter,它将内部数组作为参数。赋予filter 的函数本身就是gtehead 的组合;获取数组的第一个元素并将其与 3 进行比较:

    const arrays =
      { one:   [[1, 33, 41], [2, 0, 27], [3, 7, 9], [4,  1, 3]]
      , two:   [[1, 77,  2], [2, 6,  3], [3, 0, 0], [4, 55, 3]]
      , three: [[1,  4,  6], [2, 0,  0], [3, 5, 6], [4,  0, 0]] };
    
       map(filter(compose(gte(3), head)), arrays);
    // ^   ^      ^       ^       ^
    // A   B      C       D       E
    
    //=> { one:   [[ 1, 33, 41], [2, 0, 27], [3, 7, 9]]
    //=> , two:   [[ 1, 77,  2], [2, 6,  3], [3, 0, 0]]
    //=> , three: [[ 1,  4,  6], [2, 0,  0], [3, 5, 6]] }
    
    • 映射每个属性(A);每个数组都传递给 filter (B)
    • 每个内部数组都传递给 compose (C)
    • 取每个内部数组的头部(E)并与3比较(D

    Scott Christopher 在 cmets 中正确指出,gte 在部分应用时可能会令人困惑。事实上,整个组合都可以用这个简单的 lambda 替换:([x]) =&gt; x &lt;= 3

    我也喜欢的替代解决方案:

    map(filter(([x]) => x <= 3), arrays);
    

    【讨论】:

    • R.gte 和朋友不幸因在部分应用时会引起混乱而臭名昭著。也许是主观的,但为了便于阅读,我建议用 lambda 替换提供给R.filter 的参数以实现相同的效果(例如([x]) =&gt; x &lt;= 3
    • @ScottChristopher 同意 100%。我添加了您建议的替代答案。谢谢;)
    【解决方案3】:

    我完全赞同@customcommander 的方法, 只是想补充一点,您也可以将numerical indexes 传递给R.propSatisfies

    const headIs3OrBelow = R.propSatisfies(R.gte(3), 0);
    const fn = R.map(R.filter(headIs3OrBelow));
    
    // ===
    const data = {
      one: [[1, 33, 41], [2, 0, 27], [3, 7, 9], [4, 1, 3]],
      two: [[1, 77, 2], [2, 6, 3], [3, 0, 0], [4, 55, 3]],
      three: [[1, 4, 6], [2, 0, 0], [3, 5, 6], [4, 0, 0]],
    };
    
    console.log(
      fn(data),
    );
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous" referrerpolicy="no-referrer"&gt;&lt;/script&gt;

    也同意gte 和其他类似方法很难阅读,因为它们有点像is 3 gte than x 向后阅读...在Haskell 中你可以这样做:

    
    3 `gte` x
    

    普通方法:

    const headIs3OrBelow = ([head]) => head <= 3;
    
    const fn = (data) => Object.entries(data).reduce(
      (res, [k, lists]) => ({ ...res, [k]: lists.filter(headIs3OrBelow) }),
      {},
    );
    
    // ===
    const data = {
      one: [[1, 33, 41], [2, 0, 27], [3, 7, 9], [4, 1, 3]],
      two: [[1, 77, 2], [2, 6, 3], [3, 0, 0], [4, 55, 3]],
      three: [[1, 4, 6], [2, 0, 0], [3, 5, 6], [4, 0, 0]],
    };
    
    console.log(
      fn(data),
    );

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-30
      • 2023-02-08
      相关资源
      最近更新 更多