Javascript 换能器平坦化与uniq
我想知道是否有一种方法,通过使用一个传感器来平展列表并过滤唯一的值 通过链接,它非常容易:Javascript 换能器平坦化与uniq,javascript,recursion,ramda.js,transducer,Javascript,Recursion,Ramda.js,Transducer,我想知道是否有一种方法,通过使用一个传感器来平展列表并过滤唯一的值 通过链接,它非常容易: 从'lodash'导入{uniq,flattedeep}| 常数arr=[1,2,2,3],[1,4,5]]; uniq(展平的deep(arr));//->[1,2,3,4,5] 传感器在这里没有多大意义。您的数据结构是递归的。处理递归结构的最佳代码通常需要递归算法 传感器的工作原理 (罗曼·柳蒂科夫(Roman Liutikov)给传感器写了一封信。) 传感器都是关于用单个数据替换通过相同数据的多个
从'lodash'导入{uniq,flattedeep}|
常数arr=[1,2,2,3],[1,4,5]];
uniq(展平的deep(arr));//->[1,2,3,4,5]
传感器在这里没有多大意义。您的数据结构是递归的。处理递归结构的最佳代码通常需要递归算法
传感器的工作原理
(罗曼·柳蒂科夫(Roman Liutikov)给传感器写了一封信。)
传感器都是关于用单个数据替换通过相同数据的多个跳闸,将步骤的原子操作组合成单个操作
传感器非常适合转换此代码:
xs.map(x => x * 7).map(x => x + 3).filter(isOdd(x)).take(5)
// ^ ^ ^ ^
// \ \ \ `------ Iteration 4
// \ \ `--------------------- Iteration 3
// \ `-------------------------------------- Iteration 2
// `----------------------------------------------------- Iteration 1
变成这样:
xs.reduce((r, x) => r.length >= 5 ? res : isOdd(x * 7 + 3) ? res.concat(x * 7 - 3) : res, [])
// ^
// `------------------------------------------------------- Just one iteration
const flatten = xs => xs.reduce(
(a, x) => concat(a, isArray(x) ? flatten(x) : [x]),
[]
);
const flattenUniq = xs => Array.from(xs.reduce(
(s, x) => addAll(s, isArray(x) ? flattenUniq(x) : [x]),
new Set()
))
在Ramda中,由于map
、filter
和take
是传感器启用的,因此我们可以转换
const foo = pipe(
map(multiply(7)),
map(add(3)),
filter(isOdd),
take(3)
)
foo([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) //=> [17, 31, 45]
(在数据中迭代四次)到
它只迭代一次。(注意从管道
切换到组合
。转换器的组合顺序与普通函数的顺序相反。)
注:此类传感器的关键点在于,它们的操作方式都类似map
将一个列表转换为另一个列表,就像filter
和take
一样。虽然可以使用在不同类型上工作的传感器,map
和filter
也可以多态地在此类类型上工作,但只有在组合在同一类型上工作的函数时,它们才会一起工作
展平
不适合传感器
你的结构更复杂。虽然我们当然可以创建一个函数,以某种方式(前序、后序)对其进行爬网,并因此可能使用它启动传感器管道,但处理递归结构的逻辑方法是使用递归算法
展平此类嵌套结构的简单方法如下所示:
xs.reduce((r, x) => r.length >= 5 ? res : isOdd(x * 7 + 3) ? res.concat(x * 7 - 3) : res, [])
// ^
// `------------------------------------------------------- Just one iteration
const flatten = xs => xs.reduce(
(a, x) => concat(a, isArray(x) ? flatten(x) : [x]),
[]
);
const flattenUniq = xs => Array.from(xs.reduce(
(s, x) => addAll(s, isArray(x) ? flattenUniq(x) : [x]),
new Set()
))
(由于各种技术原因,拉姆达的代码要复杂得多。)
不过,这种递归版本并不适合使用传感器,因为传感器基本上必须一步一步地工作
Uniq
不适合传感器
另一方面,uniq与此类传感器的关系不大。问题是,如果你想从传感器中获得任何好处,uniq使用的容器必须是一个具有快速插入和快速查找功能的容器,一个集合
或一个对象
。假设我们使用一个集合
。然后我们就有了一个问题,因为我们的扁平化操作是在列表上进行的
另一种方法
由于我们无法轻松地将现有函数折叠成满足您所需的函数,因此我们可能需要一次性编写
早期解决方案的结构使添加唯一性约束变得相当容易。同样,这是:
const flatten = xs => xs.reduce(
(a, x) => concat(a, isArray(x) ? flatten(x) : [x]),
[]
);
具有用于将所有元素添加到集合的辅助函数
:
const addAll = (set, xs) => xs.reduce((s, x) => s.add(x), set)
我们可以编写一个平坦的函数,只保留唯一的值:
const flattenUniq = xs => xs.reduce(
(s, x) => addAll(s, isArray(x) ? flattenUniq(x) : [x]),
new Set()
)
注意,这与上面的结构非常相似,只切换到使用Set
,因此从concat
切换到我们的addAll
当然,最后可能需要一个数组。我们只需使用Set->Array
函数来包装它,如下所示:
xs.reduce((r, x) => r.length >= 5 ? res : isOdd(x * 7 + 3) ? res.concat(x * 7 - 3) : res, [])
// ^
// `------------------------------------------------------- Just one iteration
const flatten = xs => xs.reduce(
(a, x) => concat(a, isArray(x) ? flatten(x) : [x]),
[]
);
const flattenUniq = xs => Array.from(xs.reduce(
(s, x) => addAll(s, isArray(x) ? flattenUniq(x) : [x]),
new Set()
))
您也可以考虑将此结果保持为<代码> SET。如果您确实想要一组唯一值,那么
集合
是一个合乎逻辑的选择
这样的函数没有无点转换函数的优雅,但它可以工作,并且公开的管道使与原始数据结构和普通flatten
函数的关系更加清晰
我想你可以把这个长长的答案看作是一个冗长的方式来指出用户633183在评论中所说的:“扁平化和uniq都不是传感器的好用例。”扁平化和uniq都不是传感器的好用例谢谢@VLAZ的清理和更新链接!你改的那些短语中至少有一个相当可怕!我刚刚更新了链接,清理工作是由你完成的:PLOL。我一定是误读了历史。我很高兴我没有留下那么糟糕的文字!