how can I find duplicate values on a list,
Let's say I got a List like this:
List<Map<String, dynamic>> users = [
{ "name": 'John', 'age': 18 },
{ "name": 'Jane', 'age': 21 },
{ "name": 'Mary', 'age': 23 },
{ "name": 'Mary', 'age': 27 },
];
How I can iterate the list to know if there are users with the same name?
A simple way would be this:
void main() {
List<Map<String, dynamic>> users = [
{ "name": 'John', 'age': 18 },
{ "name": 'Jane', 'age': 21 },
{ "name": 'Mary', 'age': 23 },
{ "name": 'Mary', 'age': 27 },
];
List names = []; // List();
users.forEach((u){
if (names.contains(u["name"])) print("duplicate ${u["name"]}");
else names.add(u["name"]);
});
}
Result:
duplicate Mary
Probably a cleaner solution with extensions.
By declaring:
extension ListExtensions<E> on List<E> {
List<E> removeAll(Iterable<E> allToRemove) {
if (allToRemove == null) {
return this;
} else {
allToRemove.forEach((element) {
this.remove(element);
});
return this;
}
}
List<E> getDupes() {
List<E> dupes = List.from(this);
dupes.removeAll(this.toSet().toList());
return dupes;
}
}
then you can find your duplicates by calling List.getDupes()
Note that the function removeAll doesn't exist in my current Dart library, in case you're reading this when they implement it somehow.
Also keep in mind the equals() function. In a List<String>, ["Rafa", "rafa"] doesn't contain duplicates.
If you indeed want to achieve this level of refinement, you'd have to apply a distinctBy function:
extension ListExtensions<E> on List<E> {
List<E> removeAll(Iterable<E> allToRemove) {
if (allToRemove == null) {
return this;
} else {
allToRemove.forEach((element) {
this.remove(element);
});
return this;
}
}
List<E> distinctBy(predicate(E selector)) {
HashSet set = HashSet();
List<E> list = [];
toList().forEach((e) {
dynamic key = predicate(e);
if (set.add(key)) {
list.add(e);
}
});
return list;
}
List<E> getDupes({E Function(E) distinctBy}) {
List<E> dupes = List.from(this);
if (distinctBy == null) {
dupes.removeAll(this.toSet().toList());
} else {
dupes.removeAll(this.distinctBy(distinctBy).toSet().toList());
}
return dupes;
}
}
I had a feeling Rafael's answer had code similar to Kotlin so I dug around and saw that these functions are part of the kt_dart library which basically gets the Kotlin standard library and ports it to Dart.
I come from a Kotlin background so I use this package often. If you use it, you can simply make the extension this much shorter:
extension KtListExtensions<T> on KtList<T> {
KtList<T> get duplicates => toMutableList()..removeAll(toSet().toList());
}
just make sure to add kt_dart on your pubspec: kt_dart: ^0.8.0
Example
final list = ['apples', 'oranges', 'bananas', 'apples'].toImmutableList();
final duplicates = list.duplicates; // should be ['apples'] in the form of an ImmutableList<String>
void main() {
List<String> country = [
"Nepal",
"Nepal",
"USA",
"Canada",
"Canada",
"China",
"Russia",
];
List DupCountry = [];
country.forEach((dup){
if(DupCountry.contains(dup)){
print("Duplicate in List= ${dup}");
}
else{
DupCountry.add(dup);
}
});
}
If I have two map<string, int>s how can I swap an element from each map?
For example:
map<string, int> ps{ { "triangle", 0 }, { "cross", 1 }, { "square", 2 }, { "circle", 3 } };
map<string, int> xbox{ { "y", 0 }, { "a", 1 }, { "b", 2 }, { "x", 3 } };
swap(move(ps["cross"]), move(xbox["x"]));
The swap statement is clearly wrong, but that explains what I want to do. After the swap statement I'd like ps to contain:
{ "triangle", 0 }
{ "x", 3 }
{ "square", 2 }
{ "circle", 3 }
And xbox to contain:
{ "y", 0 }
{ "a", 1 }
{ "b", 2 }
{ "cross", 1 }
I expect there is a good way to do this with C++11's move syntax, but if possible I'd like an answer that also describes how to accomplish this on C++03.
map is implemented as an ordered tree.
You cannot simply replace a key with a new key as it might have to be placed on a different location in the tree. Consequently, you cannot swap.
Delete an re-insert the k-v pairs manually.
(As a sidenote: you haven't even told us what happens with the values...)
I want to create a map of members, but every membres have 3 propreties : first name, last name, and username. How can I create like a list of liste, but with a map.
So I want to have something like :
var membres= {['lastname': 'Bonneau',
'firstname': 'Pierre',
'username': 'mariobross'],
['lastname': 'Hamel',
'firstname': 'Alex',
'username': 'Queenlatifa'],
};
As you know, this code doesn't work. But it explain pretty well what I am trying to do.
I think you are confusing the two constructs here.
Read this introduction to the language: http://www.dartlang.org/docs/dart-up-and-running/ch02.html#lists
A list is a list of elements which can be denoted with the shorthand [...] syntax:
var list = [1, 2, "foo", 3, new Date.now(), 4];
Whereas a map can be denoted with the curly brace shorthand syntax:
var gifts = { // A map literal
// Keys Values
'first' : 'partridge',
'second' : 'turtledoves',
'fifth' : 'golden rings'
};
So, let's modify your code to work:
var members = [
{
'lastname': 'Bonneau',
'firstname': 'Pierre',
'username': 'mariobross'
},
{
'lastname': 'Hamel',
'firstname': 'Alex',
'username': 'Queenlatifa'
}
];
You can, for example, print the information like this:
members.forEach((e) {
print(e['firstname']);
});
If I understand your intent correctly, you want to have a list of maps. What you have is correct except you confused [ and {. The following works:
var membres = [
{'lastname': 'Bonneau',
'firstname': 'Pierre',
'username': 'mariobross'},
{'lastname': 'Hamel',
'firstname': 'Alex',
'username': 'Queenlatifa'}
];
As an example, to get a list of all usernames:
print(membres.map((v) => v['username']));
If you don't really need a Map, what about using a class to improve the structure of your code :
class Member {
String firstname;
String lastname;
String username;
Member(this.firstname, this.lastname, this.username);
}
main() {
final members = new List<Member>();
members.add(new Member('Pierre', 'Bonneau', 'mariobross'));
members.add(new Member('Alex', 'Hamel', 'Queenlatifa'));
// use members
}
You mean like this?
// FirstName => LastName => Value
var lookup = new Map<String, Map<String, String>>();
// get / set values like this
void setValue(String firstName, String lastName, String value) {
if (!lookUp.containsKey(firstName))
lookUp[firstName] = new Map<String, String>();
lookUp[firstName][lastName] = value;
}
String getValue(String firstName, String lastName) {
if (!lookUp.containsKey(firstName)) return "";
return lookUp[firstName][lastName];
}
First of all you need to create a map with value as list. Dont forget to initialize it
then if you want to fill it you first need to use built in function like putIfAbsent as in dart to add first object in list and then use update to add items in list. therefore you will need two arrays. First to put elements and then to add elements in list with same key. Also you can use try catch to identify if the key is present or not to do that in one loop
for (var item in days) {
var date_time = DateTime.parse(item["date"] + " 00:00:00");
_events[date_time] = _events.putIfAbsent(
date_time,
() => [
{
"title": item["title"],
"date": item["date"],
"time": reUse.get_time_am_pm_format(item["time"]),
"feature": item["feature"],
}
]);
}
for (var item in days) {
var date_time = DateTime.parse(item["date"] + " 00:00:00");
_events[date_time] = _events.update(date_time, (value) {
value.add({
"title": item["title"],
"date": item["date"],
"time": reUse.get_time_am_pm_format(item["time"]),
"feature": item["feature"],
});
return value;
});
}
How do I delete duplicates from a list without fooling around with a set? Is there something like list.distinct()? or list.unique()?
void main() {
print("Hello, World!");
List<String> list = ['abc',"abc",'def'];
list.forEach((f) => print("this is list $f"));
Set<String> set = new Set<String>.from(list);
print("this is #0 ${list[0]}");
set.forEach((f) => print("set: $f"));
List<String> l2= new List<String>.from(set);
l2.forEach((f) => print("This is new $f"));
}
Hello, World!
this is list abc
this is list abc
this is list def
this is #0 abc
set: abc
set: def
This is new abc
This is new def
Set seems to be way faster!! But it loses the order of the items :/
Use toSet and then toList
var ids = [1, 4, 4, 4, 5, 6, 6];
var distinctIds = ids.toSet().toList();
Result: [1, 4, 5, 6]
Or with spread operators:
var distinctIds = [...{...ids}];
I didn't find any of the provided answers very helpful.
Here is what I generally do:
final ids = Set();
myList.retainWhere((x) => ids.add(x.id));
Of course you can use any attribute which uniquely identifies your objects. It doesn't have to be an id field.
Benefits over other approaches:
Preserves the original order of the list
Works for rich objects not just primitives/hashable types
Doesn't have to copy the entire list to a set and back to a list
Update 09/12/21
You can also declare an extension method once for lists:
extension Unique<E, Id> on List<E> {
List<E> unique([Id Function(E element)? id, bool inplace = true]) {
final ids = Set();
var list = inplace ? this : List<E>.from(this);
list.retainWhere((x) => ids.add(id != null ? id(x) : x as Id));
return list;
}
}
This extension method does the same as my original answer. Usage:
// Use a lambda to map an object to its unique identifier.
myRichObjectList.unique((x) => x.id);
// Don't use a lambda for primitive/hashable types.
hashableValueList.unique();
Set works okay, but it doesn't preserve the order. Here's another way using LinkedHashSet:
import "dart:collection";
void main() {
List<String> arr = ["a", "a", "b", "c", "b", "d"];
List<String> result = LinkedHashSet<String>.from(arr).toList();
print(result); // => ["a", "b", "c", "d"]
}
https://api.dart.dev/stable/2.4.0/dart-collection/LinkedHashSet/LinkedHashSet.from.html
Try the following:
List<String> duplicates = ["a", "c", "a"];
duplicates = duplicates.toSet().toList();
Check this code on Dartpad.
If you want to keep ordering or are dealing with more complex objects than primitive types, store seen ids to the Set and filter away those ones that are already in the set.
final list = ['a', 'a', 'b'];
final seen = Set<String>();
final unique = list.where((str) => seen.add(str)).toList();
print(unique); // => ['a', 'b']
//This easy way works fine
List<String> myArray = [];
myArray = ['x', 'w', 'x', 'y', 'o', 'x', 'y', 'y', 'r', 'a'];
myArray = myArray.toSet().toList();
print(myArray);
// result => myArray =['x','w','y','o','r', 'a']
I am adding this to atreeon's answer. For anyone that want use this with Object:
class MyObject{
int id;
MyObject(this.id);
#override
bool operator ==(Object other) {
return other != null && other is MyObject && hashCode == other.hashCode;
}
#override
int get hashCode => id;
}
main(){
List<MyObject> list = [MyObject(1),MyObject(2),MyObject(1)];
// The new list will be [MyObject(1),MyObject(2)]
List<MyObject> newList = list.toSet().toList();
}
Remove duplicates from a list of objects:
class Stock {
String? documentID; //key
Make? make;
Model? model;
String? year;
Stock({
this.documentID,
this.make,
this.model,
this.year,
});
}
List of stock, from where we want to remove duplicate stocks
List<Stock> stockList = [stock1, stock2, stock3];
Remove duplicates
final ids = stockList.map((e) => e.documentID).toSet();
stockList.retainWhere((x) => ids.remove(x.documentID));
Using Dart 2.3+, you can use the spread operators to do this:
final ids = [1, 4, 4, 4, 5, 6, 6];
final distinctIds = [...{...ids}];
Whether this is more or less readable than ids.toSet().toList() I'll let the reader decide :)
For distinct list of objects you can use Equatable package.
Example:
// ignore: must_be_immutable
class User extends Equatable {
int id;
String name;
User({this.id, this.name});
#override
List<Object> get props => [id];
}
List<User> items = [
User(
id: 1,
name: "Omid",
),
User(
id: 2,
name: "Raha",
),
User(
id: 1,
name: "Omid",
),
User(
id: 2,
name: "Raha",
),
];
print(items.toSet().toList());
Output:
[User(1), User(2)]
Here it is, a working solution:
var sampleList = ['1', '2', '3', '3', '4', '4'];
//print('original: $sampleList');
sampleList = Set.of(sampleList).toList();
//print('processed: $sampleList');
Output:
original: [1, 2, 3, 3, 4, 4]
processed: [1, 2, 3, 4]
Using the fast_immutable_collections package:
[1, 2, 3, 2].distinct();
Or
[1, 2, 3, 2].removeDuplicates().toList();
Note: While distinct() returns a new list, removeDuplicates() does it lazily by returning an Iterable. This means it is much more efficient when you are doing some extra processing. For example, suppose you have a list with a million items, and you want to remove duplicates and get the first five:
// This will process five items:
List<String> newList = list.removeDuplicates().take(5).toList();
// This will process a million items:
List<String> newList = list.distinct().sublist(0, 5);
// This will also process a million items:
List<String> newList = [...{...list}].sublist(0, 5);
Both methods also accept a by parameter. For example:
// Returns ["a", "yk", "xyz"]
["a", "yk", "xyz", "b", "xm"].removeDuplicates(by: (item) => item.length);
If you don't want to include a package into your project but needs the lazy code, here it is a simplified removeDuplicates():
Iterable<T> removeDuplicates<T>(Iterable<T> iterable) sync* {
Set<T> items = {};
for (T item in iterable) {
if (!items.contains(item)) yield item;
items.add(item);
}
}
Note: I am one of the authors of the fast_immutable_collections package.
void uniqifyList(List<Dynamic> list) {
for (int i = 0; i < list.length; i++) {
Dynamic o = list[i];
int index;
// Remove duplicates
do {
index = list.indexOf(o, i+1);
if (index != -1) {
list.removeRange(index, 1);
}
} while (index != -1);
}
}
void main() {
List<String> list = ['abc', "abc", 'def'];
print('$list');
uniqifyList(list);
print('$list');
}
Gives output:
[abc, abc, def]
[abc, def]
As for me, one of the best practices is sort the array, and then deduplicate it. The idea is stolen from low-level languages. So, first make the sort by your own, and then deduplicate equal values that are going after each other.
// Easy example
void dedup<T>(List<T> list, {removeLast: true}) {
int shift = removeLast ? 1 : 0;
T compareItem;
for (int i = list.length - 1; i >= 0; i--) {
if (compareItem == (compareItem = list[i])) {
list.removeAt(i + shift);
}
}
}
// Harder example
void dedupBy<T, I>(List<T> list, I Function(T) compare, {removeLast: true}) {
int shift = removeLast ? 1 : 0;
I compareItem;
for (int i = list.length - 1; i >= 0; i--) {
if (compareItem == (compareItem = compare(list[i]))) {
list.removeAt(i + shift);
}
}
}
void main() {
List<List<int>> list = [[1], [1], [2, 1], [2, 2]];
print('$list');
dedupBy(list, (innerList) => innerList[0]);
print('$list');
print('\n removeLast: false');
List<List<int>> list2 = [[1], [1], [2, 1], [2, 2]];
print('$list2');
dedupBy(list2, (innerList) => innerList[0], removeLast: false);
print('$list2');
}
Output:
[[1], [1], [2, 1], [2, 2]]
[[1], [2, 1]]
removeLast: false
[[1], [1], [2, 1], [2, 2]]
[[1], [2, 2]]
This is another way...
final reducedList = [];
list.reduce((value, element) {
if (value != element)
reducedList.add(value);
return element;
});
reducedList.add(list.last);
print(reducedList);
It works for me.
var list = [
{"id": 1, "name": "Joshua"},
{"id": 2, "name": "Joshua"},
{"id": 3, "name": "Shinta"},
{"id": 4, "name": "Shinta"},
{"id": 5, "name": "Zaidan"}
];
list.removeWhere((element) => element.name == element.name.codeUnitAt(1));
list.sort((a, b) => a.name.compareTo(b.name));
Output:
[{"id": 1, "name": "Joshua"},
{"id": 3, "name": "Shinta"},
{"id": 5, "name": "Zaidan"}]
List<Model> bigList = [];
List<ModelNew> newList = [];
for (var element in bigList) {
var list = newList.where((i) => i.type == element.type).toList();
if(list.isEmpty){
newList.add(element);
}
}
Create method to remove duplicates from Array and return Array of unique elements.
class Utilities {
static List<String> uniqueArray(List<String> arr) {
List<String> newArr = [];
for (var obj in arr) {
if (newArr.contains(obj)) {
continue;
}
newArr.add(obj);
}
return newArr;
}
}
You can use the following way:
void main(List <String> args){
List<int> nums = [1, 2, 2, 2, 3, 4, 5, 5];
List<int> nums2 = nums.toSet().toList();
}
NOTE: This will not work if the items in the list are objects of class and have the same attributes. So, to solve this, you can use the following way:
void main() {
List<Medicine> objets = [Medicine("Paracetamol"),Medicine("Paracetamol"), Medicine("Benylin")];
List <String> atributs = [];
objets.forEach((element){
atributs.add(element.name);
});
List<String> noDuplicates = atributs.toSet().toList();
print(noDuplicates);
}
class Medicine{
final String name;
Medicine(this.name);
}
This is my solution
List<T> removeDuplicates<T>(List<T> list, IsEqual isEqual) {
List<T> output = [];
for(var i = 0; i < list.length; i++) {
bool found = false;
for(var j = 0; j < output.length; j++) {
if (isEqual(list[i], output[j])) {
found = true;
}
}
if (found) {
output.add(list[i]);
}
}
return output;
}
Use it like this:
var theList = removeDuplicates(myOriginalList, (item1, item2) => item1.documentID == item2.documentID);
or...
var theList = removeDuplicates(myOriginalList, (item1, item2) => item1.equals(item2));
or...
I have a library called Reactive-Dart that contains many composable operators for terminating and non-terminating sequences. For your scenario it would look something like this:
final newList = [];
Observable
.fromList(['abc', 'abc', 'def'])
.distinct()
.observe((next) => newList.add(next), () => print(newList));
Yielding:
[abc, def]
I should add that there are other libraries out there with similar features. Check around on GitHub and I'm sure you'll find something suitable.