Недавно я работал над проектом для начинающих в Scala, и у меня есть вопрос для новичков о списках Scala.
Скажем, у меня есть список кортежей (например, List[Tuple2[String, String]]). Есть ли удобный метод для возврата первого появления указанного кортежа из списка, или необходимо выполнить итерацию по списку вручную?





Вы можете попробовать использовать найти. (Обновленное местоположение поиска в scala-doc)
Если вы изучаете scala, я бы внимательно посмотрел на черту Seq. Он обеспечивает основу для большей части функционального совершенства scala.
scala> val list = List(("A", "B", 1), ("C", "D", 1), ("E", "F", 1), ("C", "D", 2), ("G", "H", 1))
list: List[(java.lang.String, java.lang.String, Int)] = List((A,B,1), (C,D,1), (E,F,1), (C,D,2), (G,H,1))
scala> list find {e => e._1 == "C" && e._2 == "D"}
res0: Option[(java.lang.String, java.lang.String, Int)] = Some((C,D,1))
@grass Каким должно быть возвращаемое значение, если тройной (C,D,1) нет в списке?
Нет, или исключение, или пустой набор. Было бы здорово, если бы был способ настроить возвращаемое значение, если тройка не найдена (кроме написания моего собственного метода find ()).
«Нет» и «Некоторые» всегда идут вместе. Они делают «Вариант [T]». Если ваша функция должна просто возвращать "T", вы должны сигнализировать об отсутствии такого случая с помощью исключения. Я скоро добавлю ответ, который, как мне кажется, обеспечивает то, что вы хотите (с помощью 'find').
Как упоминалось в предыдущем комментарии, find, вероятно, является самым простым способом сделать это. На самом деле в коллекциях Scala есть три разных метода «линейного поиска», каждый из которых возвращает немного другое значение. Какой из них вы используете, зависит от того, для чего вам нужны данные. Например, вам нужен индекс или вам просто нужно логическое значение true / false?
Не могли бы вы подробнее рассказать об этих методах «линейного поиска»? Я хочу получить индекс кортежа (имеющего только часть кортежа)
на самом деле я нашел то, что искал: .zipWithIndex.collect { case ("partOfTuple", _, i) => i }
Вы также можете сделать это, что не требует знания имен полей в классе Tuple2 - вместо этого используется сопоставление с образцом:
list find { case (x,y,_) => x == "C" && y == "D" }
«найти» хорошо, когда ты знаешь, что тебе нужен только один; если вы хотите найти все совпадающие элементы, вы можете использовать «фильтр» или эквивалентный сладкий для понимания:
for ( (x,y,z) <- list if x == "C" && y == "D") yield (x,y,z)
Ваш второй пример, похоже, больше похож на filter, то есть он вернет свойство соответствия элементов все, а не единственное первое, как того хочет автор вопроса.
Вот код, который может вам помочь.
У меня был аналогичный случай, когда я имел коллекцию записей базового класса (здесь A), из которых я хотел найти узел определенного производного класса, если таковой имеется (здесь B).
class A
case class B(val name: String) extends A
object TestX extends App {
val states: List[A] = List( B("aa"), new A, B("ccc") )
def findByName( name: String ): Option[B] = {
states.find{
case x: B if x.name == name => return Some(x)
case _ => false
}
None
}
println( findByName("ccc") ) // "Some(B(ccc))"
}
Важная часть здесь (для моего приложения) заключается в том, что findByName возвращает не Option[A], а Option[B].
Вы можете легко изменить поведение, чтобы вместо этого возвращать B и генерировать исключение, если ничего не найдено. Надеюсь это поможет.
Рассмотрим collectFirst, который доставляет Some[(String,String)] для первого совпадающего кортежа, или None в противном случае, например, следующим образом:
xs collectFirst { case t@(a,_) if a == "existing" => t }
Some((existing,str))
scala> xs collectFirst { case t@(a,_) if a == "nonExisting" => t }
None
Используя @, мы привязываем значение кортежа к t, чтобы можно было собрать весь соответствующий кортеж.
Можно ли вернуть не Some ((C, D, 1)), а (C, D, 1)? Я имею в виду то же самое, если бы я использовал list (1).