如何解决尝试使用 reduce 函数转换字符串中的对象列表时出错
我正在使用 kotlin 语言并尝试了以下代码:
data class D( val n: Int,val s: String )
val lst = listof( D(1,"one"),D(2,"two" ) )
val res = lst.reduce { acc:String,d:D -> acc + "," + d.toString() }
最后一条语句导致以下错误:
Expected parameter of type String
Expected parameter of type String
Type mismatch: inferred type is D but String was expected
虽然这个版本的最后一条语句有效:
val res = lst.map { e -> e.toString() }.reduce { acc,el -> acc + "," + el }
我不明白为什么第一个版本不起作用。找到 here 的 reduce 函数的正式定义如下:
inline fun <S,T : S> Iterable<T>.reduce(
operation: (acc: S,T) -> S
): S
但这似乎与同一页面上的以下句子形成对比:
从第一个元素开始累积值并应用 从左到右操作当前累加器值和每个 元素。
也就是说,正如所解释的那样here:
这两个函数的区别在于 fold() 需要一个 初始值并将其用作第一步的累积值, 而reduce() 的第一步使用第一个和第二个 元素作为第一步的操作参数。
但是,为了能够在第一个和第二个元素上应用 操作,依此类推,在我看来,该操作应该具有 Iterable 基类型的两个参数。 >
那么,我错过了什么?
解决方法
Reduce 在这里不是正确的工具。在这种情况下最好的函数是 joinToString
:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container1">
<input placeholder="container 1" class="inputs1" />
<input placeholder="container 1" class="inputs1" />
<input placeholder="container 1" class="inputs1" />
<input placeholder="container 1" class="inputs1" />
</div>
<div id="container2">
<input placeholder="container 2" class="inputs2" />
<input placeholder="container 2" class="inputs2" />
<input placeholder="container 2" class="inputs2" />
<input placeholder="container 2" class="inputs2" />
</div>
打印:
listOf(D(1,"one"),D(2,"two"))
.joinToString(",")
.let { println(it) }
D(n=1,s=one),D(n=2,s=two)
不是为转换类型而设计的,而是为将元素集合减少为相同类型的单个元素而设计的。您不想减少到单个 reduce
,您需要一个字符串。您可以尝试使用 fold
实现它,它类似于 D
,但需要一个您想要折叠的初始元素:
reduce
但是,这会添加一个额外的逗号:
listOf(D(1,"two"))
.fold("") { acc,d -> "$acc,$d" }
.let { println(it) }
这正是 ,D(n=1,s=two)
存在的原因。
您可以查看定义以了解为什么它不起作用
为了让它工作,你可以简单地创建一个扩展函数:
fun List<D>.reduce(operation: (acc: String,D) -> String): String {
if (isEmpty())
throw UnsupportedOperationException("Empty list can't be reduced.")
var accumulator = this[0].toString()
for (index in 1..lastIndex) {
accumulator = operation(accumulator,this[index])
}
return accumulator
}
您可以将其用作:
val res = lst.reduce { acc:String,d:D -> acc + "," + d.toString() }
或者简单地说:
val res = lst.reduce { acc,$d" }
如果需要,您可以将函数修改为更通用。
,TL;DR
您的代码 acc:String
在这一行中已经是一个错误的陈述:
val res = lst.reduce { acc:String," + d.toString() }
因为 acc
只能是 D
,永远不能是 String
! Reduce
返回与执行它的 Iterable 相同的类型,lst
是 Iterable<D>
。
说明
你已经查了reduce的定义
inline fun <S,T : S> Iterable<T>.reduce(
operation: (acc: S,T) -> S
): S
所以让我们试着把你的代码放在里面:
-
lst
的类型为List<D>
- 由于
List
扩展Iterable
,我们可以写lst : Iterable<D>
-
reduce
现在看起来像这样:
inline fun <D,T : D> Iterable<T>.reduce(
operation: (acc: D,T) -> D //String is literally impossible here,because D is not a String
): S
并写出:
lst<D>.reduce { acc:D,d:D -> }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。