【问题标题】:How to transform array of arrays into an array of objects with Ramda?如何使用 Ramda 将数组数组转换为对象数组?
【发布时间】:2019-01-04 10:03:23
【问题描述】:

背景

我有一个表示网格的数组,格式如下:

const grid = [
    [null, null, null, null, null, null, null],
    [null, null, null, null, null, null, null],
    [null, "®" , null, null, null, null, "®" ],
    ["©" , "©" , null, null, "©" , "®" , "®" ],
    ["®" , "®" , "®" , "©" , "®" , "©" , "©" ],
    ["®" , "©" , "©" , "®" , "©" , "®" , "©" ],
];

目标

我的目标是将该数组转换为以下内容:

const grid = [ 
    { row: 0, column: 1, value: null},
    { row: 0, column: 2, value: null},
    { row: 0, column: 3, value: null},
    //... some rows after ...
    { row: 3, column: 0, value: "©"},
    // etc...
];

研究

我的第一个想法是使用两个嵌套的R.mapR.chain。但是我有一个主要问题:ramda 函数确实 not 将索引作为参数(与 JavaScript 中的计数器实现不同)。

所以我相信使用 ramda 做这个练习是不可能的。

问题

有没有办法只使用 ramda 函数(没有 for 循环)来做这个练习?

【问题讨论】:

  • 你考虑过使用 vanilla JS 吗?我不知道 ramda,但我很确定您可以使用 vanilla JS 获得一个干净的功能版本来获得您的预期输出。
  • 如果问题是缺少索引,我认为ramdajs.com/0.21.0/docs/#addIndex 将能够通过装饰您需要的索引来提供帮助?大多数函数式语言都有类似的功能,例如 Scala 中的zipWithIndex
  • 我不熟悉 ramda 但它也有mapObjIndexed

标签: javascript arrays functional-programming ramda.js


【解决方案1】:

一个简单的嵌套循环就可以做到:

 const result = [];

 for(const [row, content] of grid.entries()) {
    for(const [column, value] of content.entries()) {
       result.push({ row, column, value });
    }
}

【讨论】:

  • 请允许我重复一下被问到的问题:有没有办法只使用 ramda 函数(no for 循环)来做这个练习?
【解决方案2】:

正如 cmets 中所讨论的:这是一个没有 ramda 的版本,但也没有任何 for 循环。

希望你会喜欢它;)

如您所见,完全有可能在没有任何 for 循环的情况下执行此操作,也无需像 ramda 或其他库这样的覆盖。

const grid = [
    [null, null, null, null, null, null, null],
    [null, null, null, null, null, null, null],
    [null, "®" , null, null, null, null, "®" ],
    ["©" , "©" , null, null, "©" , "®" , "®" ],
    ["®" , "®" , "®" , "©" , "®" , "©" , "©" ],
    ["®" , "©" , "©" , "®" , "©" , "®" , "©" ],
];

const result = grid.reduce((r, array, i) => [...r, ...array.map((value, j) => ({row: i, column: j, value}))], []);

console.log(result);

【讨论】:

  • 我非常清楚在没有 ramda 的情况下这样做的可能性。那不是问题。挑战在于使用它:P
【解决方案3】:

解决方案

使用@sjahan 的解决方案 使用 Ramda 的自然解决方案如下:

const R  require("ramda");
const mapIndexed = R.addIndex( R.map );
const reduceIndexed = R.addIndex( R.reduce );

const convertGrid = reduceIndexed(
  ( acc, array, i ) => [...acc, ...mapIndexed( ( value, j ) => ( { row: i, column: j, value } ), array ) ],
  [ ]
);

【讨论】:

    【解决方案4】:

    使用 Ramda 的另一种方法是映射行以添加其列索引,然后 transpose 网格,然后再次映射它以将行索引添加到每一列。

    const grid = [
        [null, null, null, null, null, null, null],
        [null, null, null, null, null, null, null],
        [null, "®" , null, null, null, null, "®" ],
        ["©" , "©" , null, null, "©" , "®" , "®" ],
        ["®" , "®" , "®" , "©" , "®" , "©" , "©" ],
        ["®" , "©" , "©" , "®" , "©" , "®" , "©" ],
    ];
    
    const mapCol = R.addIndex(R.map)(R.flip(R.assoc('column')))
    const mapRow = R.addIndex(R.map)(R.flip(R.assoc('row')))
    const mapVal = R.map(R.objOf('value'))
    
    const fn = R.pipe(
      R.map(mapVal),  // convert each value to `{ value: ... }`
      R.map(mapCol),  // add the column index `{ value: ..., column: n }`
      R.transpose,    // transpose the whole grid
      R.chain(mapRow) // add the row index `{ value: ..., column: n, row: m }`
    )
    
    console.log(fn(grid))
    <script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

    最后一次调用R.chain 只需一步即可完成映射和展平。

    请注意,这会导致列表按列升序,然后按行升序。如果您需要按照您的示例按行然后按列升序的列表,您可以像这样再次转置网格:

    const fn = pipe(
      R.map(mapVal),
      R.map(mapCol),
      R.transpose,
      R.map(mapRow),
      R.transpose,
      R.unnest
    )
    

    【讨论】:

      猜你喜欢
      • 2021-11-08
      • 1970-01-01
      • 2016-08-30
      • 1970-01-01
      • 1970-01-01
      • 2017-12-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多