I'm building some logic using streams that contains Products and Categories. Product has id, and another stuff, Category has product property of type List<String> where string represents the id of the product. I'm combining two streams, one represents the products, another the selected category, and it will produce another stream with filtered products regarding to the selected category.

import 'package:rxdart/rxdart.dart';

class ProductsScreenBloc {
  Observable<List<dynamic>> _products;
  Observable<List<dynamic>> _categories;
  final _selectedCategory = BehaviorSubject<dynamic>.seeded(null);

  ProductsScreenBloc({products, categories}) {
    _products = products;
    _categories = categories;
  }

  Observable<List<dynamic>> get products => _products;

  Observable<List<dynamic>> get productsFiltered =>
      Observable.combineLatest2(_products, selectedCategory,
          (products, category) {
        if (category == null) {
          return products;
        }
        print('click');
        final availableIds = category['products'];

        // final items = products
        //     .where((item) => availableIds.contains(item["name"]))
        //     .toList();

        final List<dynamic> items = [];
        products.forEach((product) {
          if (availableIds.contains(product["id"])) {
            items.add(product);
          }
        });

        print(items);
        print('items filtered');

        return items;
      });

  Observable<List<dynamic>> get categories => _categories;

  Observable<dynamic> get selectedCategory => _selectedCategory.stream;

  Function(dynamic) get selectCategory => _selectedCategory.sink.add;

  dispose() {
    _selectedCategory.close();
  }
}

The imperative way (forEach with adding stuff to the list) is working properly. When I use where method on the list, there is some sneaky error or something like that, it won't even print anything to the console and also every print, return, function call etc... isn't executed at all

example of the console output (where method)

flutter: click
flutter: null -- this is the value that is returned from the productsFiltered

example of the console output (foreach)

flutter: click
flutter: [array of filtered items]
flutter: items filtered
flutter: [array of filtered items] - return value from the productsFiltered

I wrote some code sample in the dartpad and both ways are working ok ¯_(ツ)_/¯

void main() {
  final one = {"name": "one"};
  final two = {"name": "two"};
  final three = {"name": "three"};
  final list = [one, two, three];
  final available = ["one", "three"];

  print(list.where((item) => available.contains(item["name"])).toList());
  // [{name: one}, {name: three}]

  final newList = [];

  list.forEach((item) {
    if (available.contains(item["name"])) {
      newList.add(item);
    }
  });

  print(newList); // [{name: one}, {name: three}]
}


Solution 1: Omatt

It looks like you're trying to use a comparator on List<Map<String, String>>. I encountered a similar issue and it turns out that List.contains() uses a == operator and is unable to perform deep comparison of Maps. As a workaround, you can try using a LinkedHashSet<Map<String, String>> instead of a List as mentioned in this comment.