如何使用Dart将列表拆分或分块为相等的部分?

时间:2014-03-08 19:34:03

标签: dart

假设我有一个列表:

var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];

我想要一个包含2个元素的列表列表:

var chunks = [['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h']];

使用Dart做到这一点的好方法是什么?

14 个答案:

答案 0 :(得分:11)

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

答案 1 :(得分:8)

Quiver(版本> = 0.18)提供partition()作为其iterables库的一部分(import'package:quiver / iterables.dart')。实现返回延迟计算的Iterable,使其非常有效。用作:

var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
var pairs = partition(letters, 2);

返回的pairs将是Iterable<List>,如下所示:

[['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h']]

答案 2 :(得分:7)

这是另一种方式:

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

答案 3 :(得分:3)

这种方式适用于奇数长度列表:

  var nums = [1, 2, 3, 4, 5];
  var pairs = new List.generate(nums.length~/2, (i) => [nums[2 * i], nums[2 * i + 1]]);

如果列表长度不均匀,也许您可​​能想要抛出错误或提供填充值。

答案 4 :(得分:3)

我建议创建一对迭代,并使用.toList,如果你真的需要它作为列表。此解决方案也可以应用于任何可迭代的,而不仅仅是列表。首先,一个只适用于列表(长度均匀)的简单解决方案(如Robert King提供的解决方案):

new Iterable.generate(letters.length ~/ 2,
                      (i) => [letters[2*i], letters[2*i + 1]])

更通用的解决方案很复杂:

class mappedIterable extends Object implements Iterable with IterableMixin {
  Function generator;

  mappedIterable(Iterable source, Iterator this.generator(Iterator in));

  Iterator get iterator => generator(source.iterator);
}

class Pairs implements Iterator {
  Iterator _source;
  List _current = null;
  Pairs(Iterator this._source);

  List get current => _current;
  bool moveNext() {
    bool result = _source.moveNext();
    _current = [_source.current, (_source..moveNext()).current];
    return result;
  }
}

Iterable makePairs(Iterable source) =>
  new mappedIterable(source, (sourceIterator) => new Pairs(sourceIterator));

print(makePairs(letters))

似乎从流中创建对流实际上更容易,而不是从迭代中生成可迭代的对。

答案 5 :(得分:1)

这是一种方式:

letters.fold([[]], (list, x) {    
  return list.last.length == 2 ? (list..add([x])) : (list..last.add(x));
});

答案 6 :(得分:1)

对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));
}

答案 7 :(得分:1)

另一种方式:

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])

答案 8 :(得分:0)

另一种解决方案;

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]]

答案 9 :(得分:0)

聚会迟到,但对于需要此功能的任何人:基于扩展的解决方案:

extension Windowed<E> on Iterable<E> {
  Iterable<List<E>> window(int size) sync* {
    if (size <= 0) throw ArgumentError.value(size, 'size', "can't be negative");
    final Iterator<E> iterator = this.iterator;
    while (iterator.moveNext()) {
      final List<E> slice = [iterator.current];
      for (int i = 1; i < size; i++) {
        if (!iterator.moveNext()) break;
        slice.add(iterator.current);
      }
      yield slice;
    }
  }
}

答案 10 :(得分:0)

在大小为 n 的相等块上拆分列表(最后一个块是剩余部分)

Iterable<List<T>> chunks<T>(List<T> lst, int n) sync* {
  final gen = List.generate(lst.length ~/ n + 1, (e) => e * n);
  for (int i in gen) {
    if (i < lst.length)
      yield lst.sublist(i, i + n < lst.length ? i + n : lst.length);
  }
}

用法示例:

chunks([2, 3, 4, 5, 6, 7, 5, 20, 33], 4).forEach(print);
chunks(['a', 'b', 'c'], 2).forEach(print);

答案 11 :(得分:0)

这是使用索引 for 循环和泛型的旧式解决方案:

List<List<T>> _generateChunks<T>(List<T> inList, int chunkSize) {
  List<List<T>> outList = [];
  List<T> tmpList = [];
  int counter = 0;

  for (int current = 0; current < inList.length; current++) {
    if (counter != chunkSize) {
      tmpList.add(inList[current]);
      counter++;
    }
    if (counter == chunkSize || current == inList.length - 1) {
      outList.add(tmpList.toList());
      tmpList.clear();
      counter = 0;
    }
  }

  return outList;
}

使用示例

main() {
  var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
  int chunkSize = 2;
  List<List<String>> chunks = _generateChunks(letters, chunkSize);
  print(chunks);
}

输出为:

[[a, b], [c, d], [e, f], [g, h]]

答案 12 :(得分:0)

我找到了一个简单的解决方案:

var subList = mylist.take(3); // take 3 items first
var subList = mylist.skip(2).take(3); // take [2..5] items

答案 13 :(得分:-1)

该函数返回给定块大小的原始数组中的子列表。

LoginActivity