单次迭代=>从Java到Scala的多个输出集合

sas*_*uke 9 java scala

我目前正在尝试将一些Java代码转换为Scala代码.挑战在于确保转换后的Scala代码与原始Java代码相比,最终不会做出非常低效的事情.例如,当尝试转换以下代码时:

class Person {
    String name;
    Integer age;
    Character gender;
}

public class TestJava {
    public static void main(String[] args) {
        final List<Person> persons = new ArrayList<>();
        final List<Person> males = new ArrayList<>();
        final List<Person> aNames = new ArrayList<>();
        final List<Person> seniors = new ArrayList<>();
        for (final Person p: persons) {
            if (p.gender == 'm') {
                males.add(p);
            }
            if (p.age >= 60) {
                seniors.add(p);                
            }
            if (p.name.startsWith("a")) {
                aNames.add(p);
            }            
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

由于Java依赖于变异,因此该代码看起来很合理.但是,现在我想将它转换为Scala等价物而不会多次循环遍历该集合(在这种情况下为3次).

我当然可以使用ListScala库中的mutable 并实现与Java相同的功能,但是想知道是否有可能以函数/ Scala方式从给定的序列/集合生成多个集合,而无需迭代集合的n时间n是标准计数.提前致谢!

Ale*_*ula 5

一种纯函数和不可变的方法是通过谓词具有将集合分成桶的泛型函数:

case class Person(name: String, age: Int, gender: String)

def bucketsByPredicate(people: Seq[Person], predicates: Seq[Person => Boolean]) = {
  people.foldLeft(predicates.map(predicate =>
    (predicate, List.empty[Person])
  )) { case (predicates, person) =>
      predicates.map { case (predicate, members) =>
        (predicate, if(predicate(person)) person :: members else members)
      }
  }.map(_._2)
}
Run Code Online (Sandbox Code Playgroud)

然后一个示例用法可能是:

val olderThan60 = (p: Person) => p.age >= 60
val male = (p: Person) => p.gender == "m"
val Seq(olderThan60People, malePeople) = bucketsByPredicate(people, Seq(olderThan60, male))
Run Code Online (Sandbox Code Playgroud)

  • 这里更实用的方法是在方法中使用可变集合,比如mutable.ListBuffer,然后调用result()并返回不可变集合.这不是纯粹的功能,但更具可读性和直观性. (6认同)