2016-03-10 2 views
1

Существует несколько библиотек, таких как Spark и другие расширения Scala, которые имеют функцию «GroupWith». Эта функция позволяет сравнивать элемент с остальной частью коллекции, а затем группировать ее с использованием одного или нескольких предикатов. По-видимому, для Scala не существует какой-либо собственной функциональности в Scala, но у них есть функция sortWith, которая ведет себя аналогично, но только сортирует элементы, а не группирует их. Если объяснение не является достаточным вот небольшим примером кода, который должен показать, что я пытаюсь сделать:Есть ли встроенная функция группировки, которая работает как функция sortWith?

val list = List(1,2,3,4,5,5) 
val groupedList = list.groupWith{ (e,c) => 
    e == c 
} 

Это очень простым пример, и я хочу делать более сложные сравнения, такие как

e + 1 == c 

Итак, вопрос в том, есть ли какие-либо встроенные функции Scala, которые это делают? Любые предложения или обходные пути?

Update: Из простых примеров дали ему кажется, это не совсем ясно, что я пытаюсь сделать, вот лучший пример: Скажем, у меня есть класс дела и список этих объектов:

case class Item(num: Int, color: String) 
val list = List(new Item(13, "red"), new Item(14,"red"), new Item(15, "blue"), new Item(16, "red")) 

list.groupWith{ (e,c) => 
    (e.num -1 == c.num || e.num + 1 == c.num) && e.color == c.color   
} 

И это должно вернуть что-то вроде этого:

res8: List[List[Item]] = List(List(Item(13,red), Item(14,red)), List(Item(15,blue)), List(Item(16,red))) 
+1

Ca вы показать нам, кто не знаком ж/Спарк groupWith, ваш результат в 'groupedList' для обоих случаях? – Teliatko

+0

Мне не хватает семантики 'groupWith'. – Teliatko

+0

Вы просто хотите, чтобы сгруппированные пары были упорядочены, то есть для (1, 3, 2, 3) и (e, e + 1) должны были возвращаться (1, 2), (2,3), (2, 3) или просто (2,3)? –

ответ

2

Вот реализация:

// Takes the list as a parameter, can use pimp-my-library if you want 
def groupWith[A](xs: List[A], f: (A, A) => Boolean) = { 
    // helper function to add "e" to any list with a member that matches the predicate 
    // otherwise add it to a list of its own 
    def addtoGroup(gs: List[List[A]], e: A): List[List[A]] = { 
    val (before, after) = gs.span(_.exists(!f(_, e))) 
    if (after.isEmpty) 
     List(e) :: gs 
    else 
     before ::: (e :: after.head) :: after.tail 
    } 
    // now a simple foldLeft adding each element to the appropriate list 
    xs.foldLeft(Nil: List[List[A]])(addtoGroup) 
} 

groupWith(list, { (e: Item, c: Item) => 
        (e.num - 1 == c.num || e.num + 1 == c.num) && e.color == c.color}) 

//| res0: List[List[groups.groups.Item]] = 
//   List(List(Item(16,red)), 
//    List(Item(15 ,blue)), 
//    List(Item(14,red), Item(13,red))) 
+0

Этот подход определенно подходит для описания того, что должна выполнять функция, но я искал что-то, что является родным для Scala (то есть что-то, что мне не нужно писать). – goodOldFashioned

+1

Ну, вам не нужно писать это самостоятельно. Я написал это для вас :) Насколько я знаю, в стандартной библиотеке ничего нет, что делает именно то, что вы хотите. –

+0

Правда, я думаю, это само по себе отвечает на мой вопрос, и это хороший ответ, который я собираюсь найти, спасибо! – goodOldFashioned

1

Не уверен, если это то, что вы хотите (проверить мои комментарии на ваш вопрос), но есть метод groupBy, определенный в GenTraversableLike, который List наследует (не только список). Вы получите:

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

scala> list.groupBy(el => el) 
res0: scala.collection.immutable.Map[Int,List[Int]] = Map(5 -> List(5, 5), 1 -> List(1), 2 -> List(2), 3 -> List(3), 4 -> List(4)) 

scala> list.groupBy(el => el + 1) 
res1: scala.collection.immutable.Map[Int,List[Int]] = Map(5 -> List(4), 6 -> List(5, 5), 2 -> List(1), 3 -> List(2), 4 -> List(3)) 

В основном вы должны предоставить функцию дискриминатора от стоимости на ключ и вы получите Map[Key, List[Value].

Это то, что вы хотите?

+0

Не совсем, я знаю функцию groupBy, но это только позволяет сравнить с самим элементом, поэтому группировка операций, основанных, например, на близости номера, невозможна с этим (я думаю). Посмотрите мое обновление, чтобы получить более четкое представление о том, что я ищу. – goodOldFashioned

Смежные вопросы