Як у Scala знайти унікальні предмети у списку


Відповіді:


24

Найефективнішим способом збереження замовлень було б використання a Setяк допоміжної структури даних:

def unique[A](ls: List[A]) = {
  def loop(set: Set[A], ls: List[A]): List[A] = ls match {
    case hd :: tail if set contains hd => loop(set, tail)
    case hd :: tail => hd :: loop(set + hd, tail)
    case Nil => Nil
  }

  loop(Set(), ls)
}

Ми можемо обернути це в деякий приємніший синтаксис, використовуючи неявне перетворення:

implicit def listToSyntax[A](ls: List[A]) = new {
  def unique = unique(ls)
}

List(1, 1, 2, 3, 4, 5, 4).unique    // => List(1, 2, 3, 4, 5)

14
Він ускладнений в даний час . Scala 2.7 не мала нічого кращого.
Даніель Шпівак

211

У 2.8 це:

List(1,2,3,2,1).distinct  // => List(1, 2, 3)

1
Імхо, 1 та 2 не є унікальними елементами у списку. Тільки 3 є. Ви створюєте список унікальних предметів зі списку, що зовсім інше.
невідомий користувач

18
Якщо це те, що ви хочете (зазвичай це не так), перейдіть до: List (1,2,3,2,1) .groupBy (x => x) .filter (_._ 2.lengthCompare (1) == 0). keySet
moveaway00

13

Прокрутіть свій власний Uniq-фільтр із збереженням замовлення:

scala> val l = List(1,2,3,3,4,6,5,6)
l: List[Int] = List(1, 2, 3, 3, 4, 6, 5, 6)

scala> l.foldLeft(Nil: List[Int]) {(acc, next) => if (acc contains next) acc else next :: acc }.reverse
res0: List[Int] = List(1, 2, 3, 4, 6, 5)

4
Насправді мені це дуже сподобалось, оскільки він дозволяє складно логічну фільтрацію. Дякую!
Борис Окунський

10

Якщо ви звертаєтесь до Розеттського коду: Створіть послідовність унікальних елементів

val list = List(1,2,3,4,2,3,4,99)
val l2 = list.removeDuplicates
// l2: scala.List[scala.Int] = List(1,2,3,4,99)

Оскільки Listнезмінна, ви не зможете змінювати початкову List, викликаючиremoveDuplicates

Попередження: як згадується у цьому твіті (!), Це не зберігає порядок:

scala> val list = List(2,1,2,4,2,9,3)
list: List[Int] = List(2, 1, 2, 4, 2, 9, 3)

scala> val l2 = list.removeDuplicates
l2: List[Int] = List(1, 4, 2, 9, 3)

Для Seq, цей метод повинен бути доступний у Scala2.8, відповідно до квитка 929 .
Тим часом вам потрібно буде визначити спеціальний статичний метод як той, який ми бачимо тут


Що робити, якщо Seq [String] не Список?
Володимир Безуглий

Телефонуйте toList, мабуть :) Або, як запропонував @Synesso, використовуйте foldLeft.
Борис Окунський

7

Імхо, всі тлумачення запитання хибні:

Як у Scala знайти унікальні предмети у списку?

Враховуючи цей список:

val ili = List (1, 2, 3, 4, 4, 3, 1, 1, 4, 1) 

єдиним унікальним елементом у списку є 2. Інші предмети не є унікальними.

ili.toSet.filter (i => ili.indexOf (i) == ili.lastIndexOf (i))

знайде.


4
більшість розробників java / scala перекладають питання про "унікальні елементи в даному списку" як "усі різні значення з даним списком", а не "всі значення, що відображаються окремо в даному списку" ... саме так кожна відповідь перед вашою інтерпретував його, а також особу, яка задає питання (хто схвалив таку відповідь). що додає прихід через 2 роки та надмірна чутливість до синтаксичного аналізу вже відповіденого запитання?
mujimu

1
@mujimu: Я не пам’ятаю, чому через два роки натрапив на це питання. Можливо, хтось закрив подібне питання як точний дублікат і зв’язав тут. Часто я намагаюся відповісти на такі запитання для себе як вправу, перш ніж шукати рішення інших; чи є у них подібне чи краще рішення, чи має сенс опублікувати моє. Тож я виявив, що інші відповіли на інше запитання. Дізнавшись, як інші розуміли питання по-іншому, я все ще вважаю, що термінологія неправильна. Значення речення не повинно оцінюватися більшістю.
невідомий користувач


2

Простий спеціальний метод - це просто додати Список до Набору та використовувати звідти:

  val l = List(1,2,3,3,3,4,5,5,6,7,8,8,8,9,9)
  val s = Set() ++ x
  println(s)

Виробляє:

> Set(5, 1, 6, 9, 2, 7, 3, 8, 4)

Це працює для Seq (або будь-якого Iterable), але не є необхідним у 2.8, де метод removeDuplicates, ймовірно, буде більш читабельним. Крім того, не впевнений у продуктивності виконання та більш продуманому перетворенні.

Також зверніть увагу на загублене замовлення.


0

list.toSet зробить це, оскільки Set за визначенням містить лише унікальні елементи


1
На це вказувалось у попередній відповіді, понад 5 років тому, на що ви говорите?
jwvh
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.