在函数式编程中将列表与绝对索引组合

问题描述 投票:0回答:1

我正在寻找一种更简单的解决方案,以函数式编程风格将字典和列表组合成单个列表。字典、列表和预期结果如下所示:

const myDictionary = new Map<string, number>([
  ['a', 4],
  ['b', 0],
  ['c', 3]
])

const myList = [
  'a',
  'b',
  'c'
]

const expectedResult = [
  [
    {'index': 0, 'payload': 'a0'},
    {'index': 1, 'payload': 'a1'},
    {'index': 2, 'payload': 'a2'},
    {'index': 3, 'payload': 'a3'}
  ],
  [],
  [
    {'index': 4, 'payload': 'c0'},
    {'index': 5, 'payload': 'c1'},
    {'index': 6, 'payload': 'c2'}
  ]
] 

如您所见,

expectedResult
内部列表的项目数是可变的。在此示例中,它等于地图
myDictionary
的值,但这只是一个示例。创建这些内部列表项的函数是确定性的,但必须以某种方式计算、匹配、组合这些值......

我的问题是,我怎样才能以实用的方式做到这一点。我可以在这里做这样的事情(我在这个项目中使用 Randa):

给定一个可以转换每个列表项的函数:

const transformListItem = (char: string, offset: number, dictionary: Map<string, number>) =>
  range(0, dictionary.get(char)).map(i => ({
    'index': i + offset,
    'payload': `${char}${i}`
  }))

那么这就是我将其组合在一起的方式:

const transformList = (list: string[], dictionary: Map<string, number>) =>

    list.map((char, listItemIndex) => {

        const listPriorToThisItem = slice(0, listItemIndex, list)
        const transformedListPriorThisItem = transformList(listPriorToThisItem, dictionary)
        const indexOffset = sum(transformedListPriorThisItem.map(a => a.length))

        return transformListItem(char, indexOffset, dictionary)
    }

const result = transformList(myList, myDictionary)

但是使用这种方法,每个列表项都会进行多次计算。所以我的问题是:如何实现这一点而不必进行两次(或多次)计算。我知道记忆的可能性,但它似乎变得更加复杂。非功能性解决方案是迭代索引变量:


const transformList = (list: string[], dictionary: Map<string, number>) => {

  let indexOffset = 0

  return list.map(char => {
    const transformedItem = transformListItem(char, indexOffset, dictionary)
    indexOffset += transformedItem.length
    return transformedItem
  }
}

const result = transformList(myList, myDictionary)

FP 中有没有更简单的模式来实现这一点?

typescript list functional-programming ramda.js
1个回答
0
投票

mapAccum
函数应该允许您映射项目,同时存储下一个项目的
index

const { range, mapAccum } = R

const transformListItem = (char, offset, dictionary) =>
  range(0, dictionary.get(char)).map(i => ({
    'index': i + offset,
    'payload': `${char}${i}`
  }))
  
const transformList = (list, dictionary) =>
  mapAccum(
    (index, char) => [
      index + dictionary.get(char),
      transformListItem(char, index, dictionary)
    ],
    0, 
    list
  )[1]

const myDictionary = new Map([['a', 4], ['b', 0], ['c', 3]])
const myList = ['a', 'b', 'c']

const result = transformList(myList, myDictionary)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.29.1/ramda.min.js" integrity="sha512-PVSAmDFNqey8GMII8s9rjjkCFvUgzfsfi8FCRxQa3TkPZfdjCIUM+6eAcHIFrLfW5CTFAwAYS4pzl7FFC/KE7Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

© www.soinside.com 2019 - 2024. All rights reserved.