代码之家  ›  专栏  ›  技术社区  ›  Flame_Phoenix

如何用ramda将数组转换成对象数组?

  •  1
  • Flame_Phoenix  · 技术社区  · 6 年前

    背景

    我有一个数组,它表示具有以下格式的网格:

    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.map 以及 R.chain 它。但是我有一个主要问题:ramda函数有 以索引为参数(与JavaScript中的计数器实现不同)。

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

    问题

    有没有一种方法只使用ramda函数来做这个练习(不适用于循环)?

    4 回复  |  直到 6 年前
        1
  •  4
  •   sjahan    6 年前

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

    希望你会喜欢;)

    正如你所看到的,完全有可能做到这一点,没有任何for循环,也没有任何覆盖,如ramda或其他lib。

    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);
        2
  •  2
  •   Flame_Phoenix    6 年前

    解决方案

    使用@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 ) ],
      [ ]
    );
    
        3
  •  1
  •   Scott Christopher    6 年前

    使用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
    )
    
        4
  •  0
  •   Jonas Wilms    6 年前

    一个简单的嵌套循环执行以下操作:

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