函数式编程风格的过滤器列表
我们有一个字符串列表,其中包含 BEGIN 和 END 标记。我们可以用函数式编程风格过滤掉 BEGIN-END 之间的元素吗?我只在 scala 中使用了这种常规(标志)方法。
val list1 =
"""992
1010
1005
1112
BEGIN
1086
1244
1107
1121
END
1223
1312
1319
1306
1469""".lines.toList
var flag = false
val filteredList = list1.filter{
def f(x: String): Boolean = {
if (x.contains("BEGIN")) {
flag = true;
return false
} else if (x.contains("END")) {
flag = false
}
flag
}
f
}
是否可以避免定义标志变量?他们如何用纯函数式语言解决这个问题?
We have a list of Strings with BEGIN and END marks as parts of this list. Can we filter out elements in-between of BEGIN-END in functional programming style? I came out only with this regular (flag) approach in scala.
val list1 =
"""992
1010
1005
1112
BEGIN
1086
1244
1107
1121
END
1223
1312
1319
1306
1469""".lines.toList
var flag = false
val filteredList = list1.filter{
def f(x: String): Boolean = {
if (x.contains("BEGIN")) {
flag = true;
return false
} else if (x.contains("END")) {
flag = false
}
flag
}
f
}
Is that possible to avoid defining the flag variable? How do they solve this in pure functional languages?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您可以使用
drop
/tail
、dropWhile
、takeWhile
函数:编辑
如评论中所述
tail<如果列表为空, /code> 将抛出异常,因此如果您希望安全起见,请使用
drop(1)
而不是tail
:这是我的版本处理多个 BEGIN 和 END 部分的算法(我的一些疯狂的东西 - 一个小状态机:)
它返回
List[List[String]]
You can use
drop
/tail
,dropWhile
,takeWhile
functions:EDIT
As mentioned in comments
tail
will throw exception if list is empty, so if you prefer to stay on the safe side usedrop(1)
instead oftail
:And here is my version of algorithm that handles several BEGIN and END sections (some crazy stuff from me - a little state machine :)
it returns
List[List[String]]
首先,列表中的每个字符串都包含从行开头开始的空格。
这是代码中最大的问题,有两种方法可以解决它。
要么修剪线条……
要么您可以在每行前面加上
|
并使用stripMargin
。然后,只需应用
takeWhile
/dropWhile
或更有效地实现即可:
编辑
我将解决方案从后到前,这会下降 (filter out) 介于
BEGIN
和END
之间的值。要保留它们:编辑 2
迎接这里的挑战...我将允许使用多个 BEGIN/END 块,但也要考虑输入可能严重畸形。如果有一个 BEGIN 而没有相应的 END 怎么办?也许连续有两个 BEGIN,或者列表在 END 之前就用完了。
定义一些规则:
无需进一步废话不多说,首先创建一个迭代器来标识输入中的每个
"BEGIN"
:给出一个列表迭代器,每个列表都从
"BEGIN"
开始然后从每个列表中获取元素这些列表,直到到达相应的
"END"
,或另一个"BEGIN"
,或者列表耗尽:最终的toList 是因为它是那时仍然是一个迭代器。您现在拥有一个列表列表,每个列表对应于“块”中的一批元素,如前面的规则所定义。
To start with, each string in your list contains the spaces from the start of the line.
This is the biggest problem in your code, and there's two ways to fix it.
Either trim the lines...
... or you can precede each line with a
|
and usestripMargin
.Then it's just a small matter of applying
takeWhile
/dropWhile
or more efficiently:
EDIT
I had the solution back to front, that would drop (filter out) values between
BEGIN
andEND
. To retain them:EDIT 2
Rising to the challenge here... I'll allow for multiple BEGIN/END blocks, but also consider that the input might be badly malformed. What if there was a BEGIN without a corresponding END? Perhaps there are two BEGINs in a row, or the list runs out before there's an END.
Defining some rules:
Without further ado, first create an iterator that identifies every
"BEGIN"
in the input:Giving an iterator of lists, each starting at a
"BEGIN"
To then take elements from each of these lists until the corresponding
"END"
is reached, or another"BEGIN"
, or the list is exhausted:The final
toList
is because it's still anIterator
at that point. You now have a List of Lists, each corresponding to a batch of elements in a "Block", as defined by the previous rules.我稍微扩展了其他人的答案,以展示列表中有两个
BEGIN
...END
块的情况。我们将使用
foldRight
在迭代之间传递状态累加器。请注意,我们使用
foldRight
来提高构建结果列表的效率,因此我们将在遇到BEGIN
之前遇到END
。我们可以同样轻松地使用
foldLeft
和reverse
最后的结果列表:I'm extending others' answers a little to present a case where there are two
BEGIN
...END
blocks in the list.We're going to use
foldRight
to pass a status accumulator between iterations.Note that we're using
foldRight
to make constructing the result list efficient, so we're going to encounterEND
before we encounterBEGIN
.We could just as easily use
foldLeft
andreverse
the result list at the end:嗯嗯。这是我的看法:
MMmm. Here's my take:
我不知道 Scala,但您可以定义一个函数,返回与子字符串匹配的下一个元素的列表中的索引,并返回找到子字符串的索引以及在匹配该子字符串之前遇到的元素列表。伪代码标头:
findSubstr(list, startIndex)
。然后构建表达式(更多伪代码):如果有帮助,我可以用 Haskell 编写这个...:)
编辑:可能还有其他方法可以做到这一点
I don't know Scala, but you can define a function that returns the index in the list of the next element that matches a substring, and returns the index where the substring was found and also the list of elements encountered until that substring was matched. A pseudocode header:
findSubstr(list, startIndex)
. Then build the expression (more pseudocode):If helpful, I could write this in Haskell... :)
EDIT: There are probably other ways to do it, too
同样,处理列表中的多个
BEGIN
...END
范围的目标相同。Again, with the same goal of dealing with multiple
BEGIN
...END
spans in the list.