问题描述
我有以下JS代码...
const collection=["Thing1","Thing2"];
const doSomething = (value)=>{
switch(value){
case "Thing1":
return {
arrayItems: ["Object 1","Object 2"]
}
break;
default:
return {
arrayItems: ["Object 3","Object 4"]
}
}
}
const result = collection.reduce(
(result,value)=> result.concat(doSomething(value).arrayItems),[]
);
console.log(result);
// doSomething returns { "arrayItems": ["Object 1","Object 2"] } for Thing1
// and { "arrayItems": ["Object 3","Object 4"] } for Thing 2
// result should be ["Object 1","Object 2","Object 3","Object 4"]
我现在想把它变成类似这样的Scala reduce ...
val collection = ["Thing 1","Thing 2"]
val result: Array[...] = collection
.reduce(
(array: Array[...],value: String) => {
val objectList = service.doSomething(value)
if (array != null && array.length > 0) {
array.concat(objectList)
} else {
objectList
}
});
// doSomething returns { "arrayItems": ["Object 1","Object 4"]
但是当我尝试这个时,我得到...
type mismatch;
found : (Array[...],String) => Array[...]
required: (java.io.Serializable,java.io.Serializable) => java.io.Serializable
val result: Array[...] = doSomething(value).reduce((array: Array[...],value: String)=>{
有没有办法做到这一点?
更新
有人要求我提供要完成的工作的背景知识,所以我要完成的基本步骤是...
- 采用字符串数组
- 在产生对象集合的那些字符串上运行reduce函数
- 在reduce函数中,我们使用字符串来调用提供对象集合的服务
- 然后将这些对象与reduce值连接起来并返回
每个答案的更新
感谢伙计,直到您提出foldLeft我才知道,但仍然需要一些工作来理解。首先是我要避免的工作循环...
var array : Array[BaseObject] = Array[BaseObject]()
collection.foreach((value: String) => {
val objectList = doSomething(value).arrayItems
array = array.concat(objectList)
});
我尝试过了...
val array: List[BaseObject] =
collection.foldLeft(List.empty[BaseObject]){
(myList,value) => {
val list : List[BaseObject] = List.from(doSomething(value).arrayList)
myList ++ list
}
};
但是有些小事一定是错的,因为当我用gson toJson
解析时,我得到了...。
{"head":{...},"next":{}}
head是对象之一,而不是整个对象。
解决方法
如果要在List
上累积...
,请首选使用FoldLeft。
在以下代码中,我假设您的String
是val result: List[String] = myCollection.foldLeft(List.empty[String]){ (myList,value) => {
val newObject = service.doSomething(value)
myList :+ newObject
}
};
:
null
也:
- 相对于可变集合,更倾向于使用不可变集合。
- 在Scala中强烈建议不要使用
val result: List[String] = myCollection.foldLeft(List.empty[String]){ (myList,value) => { myList :+ service.doSomething(value) } };
。如果您的列表为空,则什至不会执行。
您还可以使用占位符来缩短您的代码,该代码将逐渐变为:
val result: List[String] = myCollection.foldLeft(List.empty[String]){ (_,_) => _ :+ service.doSomething(_)
};
然后使用占位符
import pandas as pd
import matplotlib.pyplot as plt
# using your data to create the dataframe
df = pd.DataFrame({'all_tested': AllTested,'best_sub_tested': BestSubsetTested},index=Fams)
# display(df.head())
all_tested best_sub_tested
Item1 3 1
Item2 3 0
Item3 3 0
Item4 3 0
Item5 4 3
# plot the dataframe
df.plot.barh(figsize=(16,8))
plt.ylabel('Fams')
plt.xlabel('Tests')
plt.show()
,
主要问题是reduce
将返回与集合中包含的值相同类型的值。因此,如果您有 String 的 Array ,则{ $unwind: { path:"$subs",preserveNullAndEmptyArrays: false} }
的结果将是 String (哦, String 的任何超类型,这就是为什么在这种情况下出现奇怪的 Serializable 的原因)。reduce
有一个更通用的版本,可让您提供任何类型的输出,即foldLeft
,需要初始值。
使用它,然后使用列表而不是数组,我们可以这样写:
reduce
但是,将追加到列表效率不高,因此我们可以像这样重写它以提高性能。
我们将添加所有结果,然后反转列表以按预期顺序获取输出:
def concat(input: List[String])(f: String => List[String]): List[String] =
input.foldLeft(List.empty[String]) {
case (acc,str) => acc ++ f(str)
}
但是,这是一个非常常规的操作。我们有一个def concat(input: List[String])(f: String => List[String]): List[String] =
input.foldLeft(List.empty[String]) {
case (acc,str) => f(str) reverse_::: acc
}.reverse
类型的集合,以及一个返回A
类型集合的函数,我们想将该函数应用于原始集合的所有元素并将结果分组为一个类型的集合B
。
这就是flatMap
的工作(它更通用;因为它适用于 Monad 的任何东西,而不仅是集合的东西)。 / p>
B
我建议您看看 Scaladoc ,并遵循一些教程,以了解有关stdlib提供的所有操作的更多信息。
另外,请随时提出任何问题。
您可以看到运行here的代码。