【问题标题】:How to add an transformed object to set via iterating a list in scala如何通过迭代scala中的列表来添加转换后的对象进行设置
【发布时间】:2019-06-03 09:24:25
【问题描述】:

我是 Scala 新手,我正在尝试在 Scala 中迭代列表时转换和添加一个对象,但在语法和可能的概念方面都遇到了困难。

我想像在 JAVA 中一样实现如下所示。

public Set<Manager> promoteEmployeesToManager(List<Employee> employees) {
    Set<Manager> managers = new HashSet<Manager>();
    for(employee: employees){
        if(employee.getExprience() > 5) {
              managers.add(promoteEmployee(employee));
        }
    }
    return managers;
}

public Manager promoteEmployee(Employee employee){
    return new Manager(employee);
}

我尝试了下面的代码,但它不起作用。在saveNewManagers(newManagers.toArray); 的步骤中,newManagers 仍然是空的。

private def processEmployeePromotion(employees : List[Employee]) {
    val newManagers: Set[Manager] = Set()
    employees.asScala.map(employee => promoteEmployee(newManagers, employee))
    saveNewManagers(newManagers.toArray);
}

那么promoteEmployee方法是这样的:

private def promoteEmployee (newManagers : Set[Manager], employee: Employee){
    if(employee.getExprience() > 5) {
          managers+.(new Manager(employee));
    }
}

【问题讨论】:

  • 在您的promoteEmployee方法中,您将新经理添加到一个不存在的集合中,这个名称正确吗?

标签: scala list loops set scala-collections


【解决方案1】:

因此,您有List 的员工,而您想要List 的新经理。

def processEmployeePromotion(employees :List[Employee]) :List[Manager] =
  employees.collect{case emp if emp.getExprience() > 5 => promoteEmployee(emp)}

如果员工列表为空或没有符合晋升条件的员工,这将返回一个空的 List

【讨论】:

  • +1 表示 collect 而不是 filter + map。致 Raj:如果您仍想获得 Set[Manager] 而不是 List,您可以使用 .toSet 或更改方法的返回类型并在调用结束时添加 (scala.collectio.breakOut)
【解决方案2】:
 val managers: Set[Manager] = employees
  .iterator
  .filter(_.getExperience > 5) 
  .map(promoteEmployee)
  .toSet

【讨论】:

  • .iterator 在这种情况下有什么好处吗?另外我相信使用scala.collection.breakOut 可以避免.toMap 步骤
  • @SergGr 迭代器是惰性的,因此,将它放在这里可以避免在每一步都构建中间集合。它还使breakOut 的使用变得不必要。
【解决方案3】:

在 Scala 中,Set 默认情况下是不可变的,因此 Set 上的 + 方法返回一个新集合。

private def promoteEmployee(managers: Set[Manager], employee: Employee): Set[Manager] = 
  if (employee.getExperience > 5) {
    managers + new Manager(employee)
  } else {
     managers
  }

private def processEmployeePromotion(employees: List[Employee]): Unit = {
  val newManagers = employees.asScala.foldLeft(Set.empty[Manager]) { (managers, employee) =>
    promoteEmployee(managers, employee)
  }
  saveNewManagers(newManagers.toArray)
}

这里的主要变化是foldLeft,它基本上抽象出了循环和构建Set的想法。

另一种策略是让promoteEmployee 返回Option[Manager];您可以将Option 视为最多一个元素的集合。

private def promoteEmployee(employee: Employee): Option[Manager] =
  if (employee.getExperience > 5) {
    Option(new Manager(employee))
  } else {
     None
  }

private def promotedEmployees(employees: Iterable[Employee]): Set[Manager] =
  employees.flatMap(promoteEmployee).toSet  // NB: might not work if Manager doesn't obey the equality contract...

private def processEmployeePromotion(employees: List[Employee]): Unit = {
  saveNewManagers(promotedEmployees(employees.asScala).toArray)
}

【讨论】:

    【解决方案4】:

    当您开始使用 Scala 时,您必须习惯使用不可变数据结构、可折叠、表达式...等。如果你愿意,你仍然可以像过去使用 Java 一样使用 mutable,但首先是你应该做的。

    看看这个使用 List 中的 foldLeft 的例子:

    case class Employee(id: String, name: String, experience: Int)
    case class Manager(employee: Employee)
    
    object Your_Code extends App {
      def promoteEmployee(employee: Employee) =
        Manager(employee)
    
      def promoteEmployeesToManager(list: List[Employee]) : Set[Manager] = {
        list.foldLeft(Set[Manager]())((a, b) => if(b.experience > 5) a + promoteEmployee(b) else a)
      }
    
      val employess = List(Employee("id1", "name1", 6), Employee("id1", "name1", 4))
      println(promoteEmployeesToManager(employess))
    }
    

    【讨论】:

      猜你喜欢
      • 2019-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-25
      • 2021-09-07
      • 1970-01-01
      • 2021-09-04
      • 2020-06-01
      相关资源
      最近更新 更多