如何使用Dart将列表分割或切块成相等的部分?

61
假设我有一个列表,如下所示:
var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];

我需要一个包含2个元素的列表的列表:
var chunks = [['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h']];

使用Dart语言,有什么好的方法可以实现这个功能?
21个回答

50

还有另一种方法:

  var chunks = [];
  int chunkSize = 2;
  for (var i = 0; i < letters.length; i += chunkSize) {
    chunks.add(letters.sublist(i, i+chunkSize > letters.length ? letters.length : i + chunkSize)); 
  }
  return chunks;

dartpad 上运行它。


4
当列表元素数量不是偶数时,这个解答无法正常运行。你需要在调用sublist之前加入检查是否已经到达列表末尾,否则会出现错误,比如RangeError (end): Invalid value: Not in range 14..15, inclusive: 16。请注意不要改变原意。 - Pom12
1
chunks.add(letters.sublist(i, i+2 > letters.length ? letters.length : i + 2)); 将字母列表中从第i个元素开始的两个元素添加到块列表中,如果i+2大于列表长度,则只添加剩余的元素。 - Galeen
1
使用ListComprehension怎么样?[for (int i = 0; i < list.length; i += chunkSize) list.sublist(i, min(i + chunkSize, list.length))]通过使用min(),您不需要进行任何三元检查,并且可以确保将剩余的元素作为子列表返回,即使没有足够的元素来满足chunkSize。上述ListComprehension的结果看起来非常像quiver的partition函数的结果,正如@cbracken所描述的那样。 - Jebiel
@Pom12,我已经编辑了答案以支持不同大小的块,并添加了Dartpad链接。祝使用愉快! - genericUser

39
Quiver(版本>= 0.18)在其可迭代库(import 'package:quiver/iterables.dart')中提供了partition()函数。该实现返回一个惰性计算的Iterable,因此非常高效。使用方法如下:
var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
var pairs = partition(letters, 2);

返回的“pairs”将是一个看起来像这样的“Iterable”:
[['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h']]

27

官方Dart的collection包有一个slices扩展方法,使用方法如下:

final letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
final chunks = letters.slices(2); // [['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h']]

这是最佳的解决方案。干净、简单、易读,并由Dart团队(package:collection)维护。 - venir

24

对Seth的答案进行了轻微改进,使其适用于任何列表或块大小:

var len = letters.length;
var size = 2;
var chunks = [];

for(var i = 0; i< len; i+= size)
{    
    var end = (i+size<len)?i+size:len;
    chunks.add(letters.sublist(i,end));
}

15
  pairs(list) => list.isEmpty ? list : ([list.take(2)]..addAll(pairs(list.skip(2))));

2
为了效率,我认为使用带有索引的普通for循环是最好的选择,但尝试简洁明了也是一种乐趣。 - Alan Knight
9
这个解决方案的时间复杂度为O(n^2)。我喜欢简洁的代码,但我不确定它是否值得为此付出性能上的代价。 - Florian Loitsch

8
我找到了一个简单的解决方案:
var subList = mylist.take(3); // take 3 items first
var subList = mylist.skip(2).take(3); // take [2..5] items

7
另一种解决方案:
List chunk(List list, int chunkSize) {
  List chunks = [];
  int len = list.length;
  for (var i = 0; i < len; i += chunkSize) {
    int size = i+chunkSize;
    chunks.add(list.sublist(i, size > len ? len : size));
  }
  return chunks;
}

List nums = [1,2,3,4,5];

print(chunk(nums, 2));

// [[1,2], [3,4], [5]]

5

另一种方法:

extension IterableExtensions<E> on Iterable<E> {
  Iterable<List<E>> chunked(int chunkSize) sync* {
    if (length <= 0) {
      yield [];
      return;
    }
    int skip = 0;
    while (skip < length) {
      final chunk = this.skip(skip).take(chunkSize);
      yield chunk.toList(growable: false);
      skip += chunkSize;
      if (chunk.length < chunkSize) return;
    }
  }
}

测试:

void main() {
  test("list chunked", () {
    final emptyList = [];
    final letters = ['a', 'b', 'c', 'd', 'e', 'f'];
    final digits = List.generate(32, (index) => index);
    print(emptyList.chunked(2));
    print(letters.chunked(2));
    print(digits.chunked(2));

    print(emptyList.chunked(3));
    print(letters.chunked(3));
    print(digits.chunked(3));

    print(emptyList.chunked(5));
    print(letters.chunked(5));
    print(digits.chunked(5));
  });
}

输出:

([])
([a, b], [c, d], [e, f])
([0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], ..., [28, 29], [30, 31])
([])
([a, b, c], [d, e, f])
([0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], ..., [27, 28, 29], [30, 31])
([])
([a, b, c, d, e], [f])
([0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], ..., [25, 26, 27, 28, 29], [30, 31])

5
这里有一种方法:
letters.fold([[]], (list, x) {    
  return list.last.length == 2 ? (list..add([x])) : (list..last.add(x));
});

有更好的方法吗? - Seth Ladd

4
这种方式适用于长度为奇数的列表:
  var nums = [1, 2, 3, 4, 5];
  var pairs = new List.generate(nums.length~/2, (i) => [nums[2 * i], nums[2 * i + 1]]);

也许您希望在列表长度不是偶数时抛出错误或提供一个填充值。

什么是~符号? - Hasan A Yousef
这是用于整数除法的运算符 ~/ | 返回一个整数结果的除法 https://www.dartlang.org/guides/language/language-tour - Günter Zöchbauer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接