代码之家  ›  专栏  ›  技术社区  ›  user826955

在seq[人]中查找人和邻居

  •  2
  • user826955  · 技术社区  · 7 年前

    给定一个 Seq[Person] ,其中包含1- n Person S(至少有一个人叫“汤姆”),最简单的方法是什么? 名字是“汤姆”还有那个人 就在之前 汤姆和那个人 刚好在…之后 汤姆?

    更详细的解释:

    case class Person(name:String)
    

    名单可以任意长,但会有 至少一个条目 必须是“汤姆”。因此,这些列表可以是一个有效的案例:

    val caseOne =   Seq(Person("Tom"), Person("Mike"), Person("Dude"),Person("Frank"))
    val caseTwo =   Seq(Person("Mike"), Person("Tom"), Person("Dude"),Person("Frank"))
    val caseThree = Seq(Person("Tom"))
    val caseFour =  Seq(Person("Mike"), Person("Tom"))
    

    你明白了。因为我已经有了“汤姆”,所以任务是得到他的左邻右舍(如果它存在的话)和右邻右舍(如果它存在的话)。

    在scala中实现这一点最有效的方法是什么?


    我目前的方法:

    var result:Tuple2[Option[Person], Option[Person]] = (None,None)
    
    for (i <- persons.indices)
    {
      persons(i).name match
      {
        case "Tom" if i > 0 && i < persons.size-1 => result = (Some(persons(i-1)), Some(persons(i+1))) // (...), left, `Tom`, right, (...)
        case "Tom" if i > 0                       => result = (Some(persons(i-1)), None)               // (...), left, `Tom`
        case "Tom" if i < persons.size-1          => result = (Some(persons(i-1)), None)               // `Tom`, right, (...)
        case "Tom"                                => result = (None, None)                             // `Tom`
      }
    }
    

    只是不觉得我在做 斯卡拉路 .


    Mukesh Prajapati的解决方案:

    val arrayPersons = persons.toArray
    val index = arrayPersons.indexOf(Person("Tom"))
    
    if (index >= 0)
       result = (arrayPersons.lift(index-1), arrayPersons.lift(index+1))
    

    很短,似乎覆盖了所有的情况。


    Anuj Saxena的解决方案

    result = persons.sliding(3).foldLeft((Option.empty[Person], Option.empty[Person]))
    {
        case ((Some(prev), Some(next)), _)            => (Some(prev), Some(next))
        case (_, prev :: Person(`name`) :: next :: _) => (Some(prev), Some(next))
        case (_, _ :: prev :: Person(`name`) :: _)    => (Some(prev), None)
        case (_, Person(`name`) :: next :: _)         => (None, Some(next))
        case (neighbours, _) => neighbours
    }
    
    5 回复  |  直到 7 年前
        1
  •  2
  •   mukesh210    7 年前

    首先找出“tom”所在的索引,然后使用“lift”。“lift”将部分函数转换为返回 Option 结果:

    index = persons.indexOf("Tom")
    doSomethingWith(persons.lift(index-1), persons.lift(index+1))
    
        2
  •  1
  •   anuj saxena    7 年前

    经验法则:我们不应该使用索引访问列表/序列的内容,因为它容易出错(如 IndexNotFoundException )

    如果我们想使用索引,最好使用 Array 因为它为我们提供了随机访问。

    所以对于当前的解决方案,这里是我的代码,用于在 Seq List :

      def findNeighbours(name: String, persons: Seq[Person]): Option[(Person, Person)] = {
        persons.sliding(3).flatMap{
          case prev :: person :: next :: Nil if person.name == name => Some(prev, next)
          case _ => None
        }.toList.headOption
      }
    

    这里是返回类型 Option 因为我们可能在这里找不到它(如果列表中只有一个人,或者所需的人不在列表中)。

    此代码将在 person 在参数中提供。

    如果您有可能为所提供的人员出现多个事件,请删除函数最后一行中的head选项。 findNeighbours . 然后它将返回一个元组列表。

    更新

    如果 Person 是一个case类,那么我们可以像这样使用deep-match:

      def findNeighbours(name: String, persons: Seq[Person]): Option[(Person, Person)] = {
        persons.sliding(3).flatMap{
          case prev :: Person(`name`) :: next :: Nil => Some(prev, next)
          case _ => None
        }.toList.headOption
      }
    

    对于您的解决方案,需要向其添加更多的案例(如果只有一个答案,请将其更改为使用foldleft):

      def findNeighboursV2(name: String, persons: Seq[Person]): (Option[Person], Option[Person]) = {
    persons.sliding(3).foldLeft((Option.empty[Person], Option.empty[Person])){
        case ((Some(prev), Some(next)), _) => (Some(prev), Some(next))
        case (_, prev :: Person(`name`) :: next :: _) => (Some(prev), Some(next))
        case (_, _ :: prev :: Person(`name`) :: _) => (Some(prev), None)
        case (_, Person(`name`) :: next :: _) => (None, Some(next))
        case (neighbours, _) => neighbours
    }
    

    }

        3
  •  0
  •   Mahmoud Hanafy    7 年前

    您可以使用滑动功能:

    persons: Seq[Person] = initializePersons()
    persons.sliding(size = 3).find { itr =>
      if (itr(1).name = "Tom") {
        val before = itr(0)
        val middle = itr(1)
        val after = itr(2)
      }
    }
    
        4
  •  0
  •   Metropolis    7 年前

    如果你知道在你的 Seq 使用 indexOf 而不是手动循环:

    tomIndex = persons.indexOf("Tom")
    doSomethingWith(persons(tomIndex-1), persons(tomIndex+1))
    
        5
  •  0
  •   Felix    7 年前
    // Start writing your ScalaFiddle code here
    case class Person(name: String)
    
    val persons1 = Seq(Person("Martin"),Person("John"),Person("Tom"),Person("Jack"),Person("Mary"))
    val persons2 = Seq(Person("Martin"),Person("John"),Person("Tom"))
    val persons3 = Seq(Person("Tom"),Person("Jack"),Person("Mary"))
    val persons4 = Seq(Person("Tom"))
    
    def f(persons:Seq[Person]) = 
      persons
        .sliding(3)
        .filter(_.contains(Person("Tom")))
        .maxBy {
          case _ :: Person("Tom") :: _ => 1
          case _                       => 0
        }
        .toList
        .take(persons.indexOf(Person("Tom")) + 2) // In the case where "Tom" is first, drop the last person
        .drop(persons.indexOf(Person("Tom")) - 1) // In the case where "Tom" is last, drop the first person
    
    println(f(persons1)) // List(Person(John), Person(Tom), Person(Jack))
    println(f(persons2)) // List(Person(John), Person(Tom))
    println(f(persons3)) // List(Person(Tom), Person(Jack))
    println(f(persons4)) // List(Person(Tom))
    

    Scalafiddle

    推荐文章