'Flutter Sort array by other array values

I have data like this

[{"name": "swimming"},{"name": "Politics"},{"name": "Gamer"}]

and I have profiles like

[
   {
      "username":"abc",
      "passions":[
         {
            "name":"Snooker"
         }
      ]
   },
   {
      "username":"abc",
      "passions":[
         {
            "name":"Coding"
         }
      ]
   },
   {
      "username":"xyz",
      "passions":[
         {
            "name":"swimming"
         }
      ]
   },
   {
      "username":"abc",
      "passions":[
         {
            "name":"Politics"
         },
         {
            "name":"swimming"
         }
      ]
   }
]

What I need to do is show first those profiles whose passions are matching with that first data array and then the other rest remaining will show.



Solution 1:[1]

I'm sure there are better ways to do this, but this works.

  final passions = [{"name": "swimming"},{"name": "Politics"},{"name": "Gamer"}];
  
  final users = 
[
   {
      "username":"abc",
      "passions":[
         {
            "name":"Snooker"
         }
      ]
   },
   {
      "username":"efg",
      "passions":[
         {
            "name":"Coding"
         }
      ]
   },
   {
      "username":"hij",
      "passions":[
         {
            "name":"swimming"
         }
      ]
   },
   {
      "username":"klm",
      "passions":[
         {
            "name":"Politics"
         },
         {
            "name":"swimming"
         }
      ]
   }
];
  
  var matches = [];
  
  users.forEach((u) {
    passions.forEach((p) {
      if (p['name'] == (u['passions'] as List)[0]['name']) {
        matches.add(u['username']);
      }
    });
  });
  
  print(matches.toString());

Solution 2:[2]

Just give this function a profile list and Finally returns the sort list

  List passions = [{"name": "swimming"}, {"name": "Politics"}, {"name": "Gamer"} ];

  List sortListPrfile(List profiles) {
    //profiles is a list of result server
    List _items = []; // It will be returned eventually
    List _noItemCommon = []; //Items that are not common
    for (var profile in profiles) {
      for (var passion in passions) {
        if (profile["passions"][0]["name"] == passion['name']) {
          _items.add(profile);
        } else {
          _noItemCommon.add(profile);
        }
      }
    }
    _items.addAll(_noItemCommon);
    return _items;
  }

Solution 3:[3]

Here is a function that returns the complete list by matches first and by sorted users. Your code has a nested list object that needs to check for values that way is function has one line more :)

Note: This function is only for your current item which matches object keys. To make it more secure you should add guards.

import 'package:flutter/foundation.dart';

void main() {
  final filtered = filteredByMatchesFirst(arr, matches);

  for (var value in filtered) {
    print(value);
  }
}

var matches = <Map<String, dynamic>>[
  {"name": "swimming"},
  {"name": "Politics"},
  {"name": "Gamer"},
];

var arr = <Map<String, dynamic>>[
  {
    "username": "abc",
    "passions": [
      {"name": "Snooker"}
    ]
  },
  {
    "username": "abc",
    "passions": [
      {"name": "Coding"}
    ]
  },
  {
    "username": "xyz",
    "passions": [
      {"name": "swimming"}
    ]
  },
  {
    "username": "byz",
    "passions": [
      {"name": "Gamer"}
    ]
  },
  {
    "username": "abc",
    "passions": [
      {"name": "Politics"},
      {"name": "swimming"}
    ]
  }
];

List<Map<String, dynamic>> filteredByMatchesFirst(
  List<Map<String, dynamic>> list,
  List<Map<String, dynamic>> matches,
) {
  // Sort list by users first.
  list.sort((m1, m2) {
    return (m1['username'] as String).compareTo(m2['username'] as String);
  });
  
  // Filter only match values.
  var filtered = list.where((map) {
    final passions = map['passions'] as List<Map<String, dynamic>>;
    return passions.any((a) => matches.any((b) => mapEquals(a, b)));
  }).toList();
  
  // Add the rest to the filtered list without duplicates.
  return filtered.followedBy(list).toSet().toList();
}

Output:

{username: abc, passions: [{name: Politics}, {name: swimming}]}
{username: byz, passions: [{name: Gamer}]}
{username: xyz, passions: [{name: swimming}]}
{username: abc, passions: [{name: Snooker}]}
{username: abc, passions: [{name: Coding}]}

Output without matching:

{username: abc, passions: [{name: Snooker}]}
{username: abc, passions: [{name: Coding}]}
{username: abc, passions: [{name: Politics}, {name: swimming}]}
{username: byz, passions: [{name: Gamer}]}
{username: xyz, passions: [{name: swimming}]}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 jbmcle
Solution 2 behnam bagvand
Solution 3