微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

尝试使用 reduce 函数转换字符串中的对象列表时出错

如何解决尝试使用 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,永远不能是 StringReduce 返回与执行它的 Iterable 相同的类型,lstIterable<D>

说明

你已经查了reduce的定义

inline fun <S,T : S> Iterable<T>.reduce(
    operation: (acc: S,T) -> S
): S

所以让我们试着把你的代码放在里面:

  1. lst 的类型为 List<D>
  2. 由于List扩展Iterable,我们可以写lst : Iterable<D>
  3. 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 举报,一经查实,本站将立刻删除。