在 Seq[Person] 中查找 person 和直接邻居
Find person and immediate neighbours in Seq[Person]
给定一个 Seq[Person]
,其中包含 1-n Person
s(以及最小的 1 Person beeing "Tom"),什么是找到名称为 "Tom" 的 Person
以及 就在 Tome 之前的人和 就在 [=49= 之后的人的最简单方法] 汤姆?
更详细的解释:
case class Person(name:String)
人员名单可以任意长,但 至少有一个条目 ,必须是 "Tom"。所以这些列表可以是一个有效的案例:
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"))
你懂的。由于我已经有了"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`
}
}
感觉我不是在用 scala 的方式。
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
}
可以使用滑动功能:
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)
}
}
如果您知道 Seq
中只有一个 "Tom" 实例,请使用 indexOf
而不是手动循环:
tomIndex = persons.indexOf("Tom")
doSomethingWith(persons(tomIndex-1), persons(tomIndex+1))
首先找出 "Tom" 所在的索引,然后使用 "lift"。 "lift" 将部分函数转换为返回 Option
结果的普通函数:
index = persons.indexOf("Tom")
doSomethingWith(persons.lift(index-1), persons.lift(index+1))
一个经验法则:我们永远不应该使用索引访问列表/序列的内容,因为它容易出错(比如 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
}
这里return类型在Option
因为有可能我们在这里找不到(如果只有一个人在列表中或者所需的人不在列表)。
此代码将在第一次出现参数中提供的 person
时选择对。
如果您认为所提供的人可能出现多次,请删除函数最后一行中的 headOption findNeighbours
。然后它将return一个元组列表。
更新
如果 Person
是 class 那么我们可以像这样使用深度匹配:
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
}
}
// 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))
给定一个 Seq[Person]
,其中包含 1-n Person
s(以及最小的 1 Person beeing "Tom"),什么是找到名称为 "Tom" 的 Person
以及 就在 Tome 之前的人和 就在 [=49= 之后的人的最简单方法] 汤姆?
更详细的解释:
case class Person(name:String)
人员名单可以任意长,但 至少有一个条目 ,必须是 "Tom"。所以这些列表可以是一个有效的案例:
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"))
你懂的。由于我已经有了"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`
}
}
感觉我不是在用 scala 的方式。
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
}
可以使用滑动功能:
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)
}
}
如果您知道 Seq
中只有一个 "Tom" 实例,请使用 indexOf
而不是手动循环:
tomIndex = persons.indexOf("Tom")
doSomethingWith(persons(tomIndex-1), persons(tomIndex+1))
首先找出 "Tom" 所在的索引,然后使用 "lift"。 "lift" 将部分函数转换为返回 Option
结果的普通函数:
index = persons.indexOf("Tom")
doSomethingWith(persons.lift(index-1), persons.lift(index+1))
一个经验法则:我们永远不应该使用索引访问列表/序列的内容,因为它容易出错(比如 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
}
这里return类型在Option
因为有可能我们在这里找不到(如果只有一个人在列表中或者所需的人不在列表)。
此代码将在第一次出现参数中提供的 person
时选择对。
如果您认为所提供的人可能出现多次,请删除函数最后一行中的 headOption findNeighbours
。然后它将return一个元组列表。
更新
如果 Person
是 class 那么我们可以像这样使用深度匹配:
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
}
}
// 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))