Разделение списка на определенное количество подсписков - PullRequest
4 голосов
/ 21 мая 2010

Я хочу разделить список на «определенное количество» подсписков.

То есть, например, если у меня есть список List(34, 11, 23, 1, 9, 83, 5) и ожидаемое количество подсписков равно 3, тогда я хочу List(List(34, 11), List(23, 1), List(9, 83, 5)).

Как мне это сделать? Я пытался grouped, но, похоже, он не выполняет то, что я хочу.

PS: Это не домашнее задание. Пожалуйста, дайте прямое решение вместо некоторых смутных предложений.

EDIT:

Небольшое изменение в требованиях ...

Учитывая список List(34, 11, 23, 1, 9, 83, 5) и количество подсписков = 3, я хочу, чтобы вывод был List(List(34), List(11), List(23, 1, 9, 83, 5)). (т.е. 1 элемент в списке, кроме последнего списка, который содержит все остальные элементы.)

Ответы [ 5 ]

4 голосов
/ 22 мая 2010

В ответ на ваши измененные требования

def splitN[A](list: List[A], n: Int): List[List[A]] =
  if(n == 1) List(list) else List(list.head) :: splitN(list.tail, n - 1)
2 голосов
/ 21 мая 2010

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

l.grouped( (l.length+2)/3 ).toList

будет производить что-то похожее на то, что вы хотите (если val l = List(34, 11, 23, 1, 9, 83, 5), тогда вы получите List(List(34, 11, 23), List(1, 9, 83), List(5)) обратно. Но если вы хотите примерно равное распределение по спискам, вам придется создать собственный метод, чтобы сделать это - нет библиотечной функции, которая делит список поровну на n частей.

Что-то вроде этого сработало бы, если вы хотите сохранить части в порядке:

def chopList[T](
  l: List[T], pieces: Int,
  len: Int = -1, done: Int = 0, waiting: List[List[T]]=Nil
): List[List[T]] = {
  if (l isEmpty) waiting.reverse
  else {
    val n = (if (len<0) l.length else len)
    val ls = l.splitAt( (n.toLong*(done+1)/pieces - n.toLong*done/pieces).toInt )
    chopList(ls._2,pieces,n,done+1,ls._1 :: waiting)
  }
}

и это происходит, чтобы вернуть именно то, что вы хотите: List(List(34, 11), List(23, 1), List(9, 83, 5)).

Если вы не хотите запрашивать длину списка, вы можете написать метод, который создает группу блоков и добавляет по очереди каждый новый элемент.

2 голосов
/ 21 мая 2010

Это сложный вызов, потому что вы не знаете, сколько элементов поместить в каждый список, прежде чем узнаете размер списка. Если вы действительно знаете размер списка, вы можете использовать сгруппированные: list.grouped((list.size + 2) / 3).toList. Однако он не разделит элементы, как вы.

Вопрос: имеет ли значение заказ? Если порядок элементов не нужно сохранять, то есть лучшие способы сделать это.

0 голосов
/ 21 мая 2010

Является ли grouped новым в 2.8? Самодельное решение для 2.7.7 может выглядеть так:

def splitTo (li: List [Int], count: Int) : List [List [Int]] = {
    val size = li.length / count

    if (count > 1) li.take (size) :: splitTo (li.drop (size), count-1) else 
        li :: Nil
} 

Параметризация для списка [T] оставлена ​​в качестве упражнения для читателя.

0 голосов
/ 21 мая 2010

Не знаю, это ответ на вашу проблему, но вот попытка (что вы ожидаете, когда счет находится за пределами диапазона)?

def group[T](list:List[T], count:Int):List[List[T]] = {
  if (count <= 0 || count >= list.length)
    List(list)
  else {
    val numElm = list.length / count
    def loop(list:List[T], i:Int):List[List[T]] = {
      i match {
        case 0 => List(list) 
        case 1 => List(list)
        case _ =>  {
          val l = list.splitAt(numElm)
          l._1 :: loop(l._2, i-1)
        }
      }
    }
    loop(list, count)
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...