How to flatten a List?

2020-02-24 07:44发布

问题:

How can I easily flatten a List in Dart?

For example:

var a = [[1, 2, 3], ['a', 'b', 'c'], [true, false, true]];
var b = [1, 2, 3, 'a', 'b', 'c', true, false, true];

How do I turn a into b, i.e. into a single List containing all those values?

回答1:

The easiest way I know of is to use Iterable.expand() with an identity function. expand() takes each element of an Iterable, performs a function on it that returns an iterable (the "expand" part), and then concatenates the results. In other languages it may be known as flatMap.

So by using an identity function, expand will just concatenate the items. If you really want a List, then use toList().

var a = [[1, 2, 3], ['a', 'b', 'c'], [true, false, true]];
var flat = a.expand((i) => i).toList();


回答2:

I don't think there's a built-in method for that, but you can always reduce it to a single value:

var a = [[1, 2, 3], ['a', 'b', 'c'], [true, false, true]];

var flatten = a.reduce([], (p, e) {
  p.addAll(e);
  return p;
});

print(flatten);

I wish addAll() would return the original list. Currently it returns nothing. If that were true, you could write a single liner: a.reduce([], (p, e) => p.addAll(e)).

Alternatively, you can just loop through the list and add:

var flatten = [];
a.forEach((e) => flatten.addAll(e));


回答3:

the solution with expand method fits good to satisfy this case :

expect(ListTools.getFlatList([[1],["hello",2],["test"]]),orderedEquals([1,"hello",2,"test"]));

But not for theses ones

expect(ListTools.getFlatList([[1],["hello",2,["foo",5]],["test"]]),orderedEquals([1,"hello",2,"foo",5,"test"]));
expect(ListTools.getFlatList([1,["hello",2],"test"]),orderedEquals([1,"hello",2,"test"]));

To satisfy theses test cases, you need something more recursive like the following function :

List getFlatList(List list) {
  List internalList = new List();
  list.forEach((e) {
    if (e is List) {
      internalList.addAll(getFlatList(e));
    } else {
      internalList.add(e);
    }
  });
  return internalList;
}

Best regards,

Sébastien



回答4:

You can do this efficiently with a generator:

Iterable<T> flatten<T>(Iterable<Iterable<T>> items) sync* {
  for (var i in items) {
    yield* i;
  }
}

Iterable<X> flatMap<T,X>(Iterable<Iterable<T>> items, X Function(T) f) =>
  flatten(items).map(f);



标签: dart