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。我一定是误读了历史。我很高兴我没有留下那么糟糕的文字!