Dart equivalent to Python zip and list comprehension for generating list of widgets from two lists

Question:

I want to create a list of widgets MyWidget(categoryName, color) from the following two lists.

  static const _categoryNames = <String>[
    'Length',
    'Area',
    'Volume',
  ];

  static const _baseColors = <Color>[
    Colors.teal,
    Colors.orange,
    Colors.pinkAccent,
  ];

In Python I would use a list comprehension with zip to get the result.

my_widget_list = [MyWidget(categoryName, baseColor) for categoryName, baseColor in zip(_categoryNames, _baseColors)]

Googling for a similar method for Dart did not provide any satisfactory solution.

Asked By: MachineLearner

||

Answers:

There is a zip function from package:quiver. Combined with collection-for (Dart’s equivalent to Python list comprehensions) can get you most of the way there. Dart does not have Python’s automatic unpacking, so unfortunately you won’t get nice variable names:

my_widget_list = [
  for (var pair in zip([_categoryNames, _baseColors]))
    MyWidget(pair[0], pair[1]),
]
Answered By: jamesdlin

If your aim is to create a list of widgets (assuming both your lists will have same number of elements). You can try

List<Widget> getWidgets() {

  List<Widget> my_widget_list = [];
  const _categoryNames = <String>[
    'Length',
    'Area',
    'Volume',
  ];

 const _baseColors = <Color>[
    Colors.teal,
    Colors.orange,
    Colors.pinkAccent,
  ];

  for (int i = 0; i <= _categoryNames.length -1 ; i++){
    my_widget_list.add(MyWidget(_categoryNames[i],_baseColors[i]));
  }

  return my_widget_list;
  }

Widget MyWidget(String categoryName, Color baseColor){
  return Container(
    color: baseColor,
    child: Text(categoryName,));
}
Answered By: Pratheesh Russell

"Pythonic" Dart Syntax

You can do something that looks very similar to Python using Control Flow Collections.

    List<Widget> myWidgetList = [
      for (String name in categoryNames)
        for (Color color in baseColors)
          if (baseColors.indexOf(color) == categoryNames.indexOf(name))
            myWidget(name, color)
    ];

Maybe a little less "Pythonic" but more concise . . .

    List<Widget> myWidgetList = [
      for (String name in categoryNames)
        myWidget(name, baseColors[categoryNames.indexOf(name)])
    ];

Specifically, you should read over Control Flow Collections: Composing

Complete Unit Test

For you convenience here is a quick unit-test you can run.

import 'dart:core';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  test('build list of widgets with composing', () {
    List<Widget> myWidgetList = [
      for (String name in categoryNames)
        for (Color color in baseColors)
          if (baseColors.indexOf(color) == categoryNames.indexOf(name))
            myWidget(name, color)
    ];

    List<Widget> myOtherWidgetList = [
      for (String name in categoryNames)
        myWidget(name, baseColors[categoryNames.indexOf(name)])
    ];

    expect(myWidgetList.length, equals(myOtherWidgetList.length));
    expect(myWidgetList.toString(), equals(myOtherWidgetList.toString()));
    print(myWidgetList);
  });
}

const categoryNames = <String>[
  'Length',
  'Area',
  'Volume',
];
const baseColors = <Color>[
  Colors.teal,
  Colors.orange,
  Colors.pinkAccent,
];

Widget myWidget(String categoryName, Color baseColor) {
  return Container(
      color: baseColor,
      child: Text(
        categoryName,
      ));
}
Answered By: 0p3r4t0r
Answered By: netos23