Removing duplicates from list of lists - dart

I'm having issues attempting to remove duplicate lists within a list. For example, using the list below, I need to remove one of the [2, 9] elements from the list.
List listOfLists = [[1, 5], [2, 9], [10, 12], [-1, 4], [2, 9]];
I have tried using toSet, but it only seems to work with a list of int or strings:
List uniqueLists = listOfLists.toSet().toList();
I have been stuck on this all morning, I'm sure its something simple, but the solution isn't coming to me. Any help would be appreciated.

The issue is that == for lists is reference equality, not based on the value of the lists.
for example if you run this program:
void main() {
print([2, 9] == [2, 9]);
}
it will print false.
You can create a HashSet (or LinkedHashSet if you want to preserve the order) with custom equals and hashcode functions.
import 'dart:collection';
import 'package:collection/collection.dart';
void main() {
List<List<int>> listOfLists = [
[1, 5],
[2, 9],
[10, 12],
[-1, 4],
[2, 9],
];
Set<List<int>> uniqueLists = HashSet<List<int>>(
equals: const ListEquality().equals,
hashCode: const ListEquality().hash,
)..addAll(listOfLists);
print(uniqueLists);
}
This solution uses the collection package for the ListEquality class.

This solution traverses the list backwards, and removes the last item when a duplicate is found. To compare lists, _listsAreEqual is used which is taken from this answer.
Less elegant compared to other solutions, but it does not require any additional packages.
bool _listsAreEqual(list1, list2) {
var i=-1;
return list1.every((val) {
i++;
if (val is List && list2[i] is List) {
return _listsAreEqual(val,list2[i]);
} else {
return list2[i] == val;
}
});
}
List _removeDuplicates(list) {
for (var i=list.length-1; i>0; i--) {
for (var j=i-1; j>=0; j--) {
if (_listsAreEqual(list[i], list[j])) {
list.removeAt(i);
break;
}
}
}
return list;
}
void main(){
List listOfLists = [[1, 5], [2, 9], [10, 12], [-1, 4], [2, 9]];
List uniqueLists = _removeDuplicates(listOfLists);
//List uniqueLists = _removeDuplicates(List.from(listOfLists)); // leave original list unmodified
print(uniqueLists);
}
If you do not want the original list to be modified, use the commented statement instead to create a copy of the original list.

Thank you for your help. Not sure why I didn't find this previously, but this does the trick perfectly.
List uniqueList = listOfLists.map((f) => f.toString()).toSet().toList().map((f) => json.decode(f) as List<dynamic>).toList();

Related

Use reduce method in dart to group consecutive elements in the list like in Javascript

I have following codes in javascript
var ArrayLogs = [1, 3, 5, 4, 9, 11, 0, -4, -10];
var newLogArrays = [];
ArrayLogs.reduce(function(result, value, index, array) {
if (index % 2 === 0){
newLogArrays.push(array.slice(index, index + 2));
}
return newLogArrays;
}, []);
Above method outputs:
[[1,3],[5,4],[9,11],[0,-4],[-10]]
I am looking equivalent code in Dart, I know there is reduce method in dart as well, but I am not sure how to use to get similar result as javascript.
Any help will be highly appreciated.
Thanks
If you just want to do it using Dart only, you can do something like the following:
void main() {
final arrayLogs = [1, 3, 5, 4, 9, 11, 0, -4, -10];
final result = arrayLogs.fold<List<List<int>>>([], (list, element) {
if (list.isEmpty || list.last.length > 1) {
return list..add([element]);
} else {
return list..last.add(element);
}
});
print(result);
// [[1, 3], [5, 4], [9, 11], [0, -4], [-10]]
}
I am sure there are some packages which can do this more automatically or cleaner.

Why can't I assign a shuffled array to a new array

Why can't I assign a shuffled array to a new array?
For example, this is my list:
List nums = [1, 2, 3];
List newlist=nums.shuffle();
However, this does not work for me.
Because shuffle() on List does not return anything (which is indicated by void which means the method does not return anything usable) but are instead shuffling the list you are calling the method on.
void shuffle([Random? random])
Shuffles the elements of this list randomly.
https://api.dart.dev/stable/2.15.1/dart-core/List/shuffle.html
If you want to output your nums list after it have been shuffled, you just need to print nums like this after the nums.shuffle() call:
void main() {
final nums = [1, 2, 3];
nums.shuffle();
print(nums); // [2, 3, 1]
}
If you want to have a new list there is shuffled and based on another list, you can do something like this (the .. is called a cascade call, you can read more about it here: https://dart.dev/guides/language/language-tour#cascade-notation):
void main() {
final nums = [1, 2, 3];
final shuffeledNums = nums.toList()..shuffle();
print(nums); // [1, 2, 3]
print(shuffeledNums); // [2, 1, 3]
}
Which is the same as this without the use of cascade:
void main() {
final nums = [1, 2, 3];
final shuffeledNums = nums.toList();
shuffeledNums.shuffle();
print(nums); // [1, 2, 3]
print(shuffeledNums); // [2, 1, 3]
}

How can i find sum of three element in a given away

Is there a method we use to reach the desired number in an array given in dart language.. I can do this for binary ones, but I can't do it for a code that finds the sum of 3 or more elements
For example
Input: candidates = [10,1,2,7,6,1,5], target = 8
Output:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
this is the my code i have done until now
void main() {
var candidates = [10, 1, 2, 7, 6, 1, 5], target = 8;
var answer = [];
for (int i = 0; i < candidates.length; i++) {
for (int j = 0; j < candidates.length; j++) {
if (candidates[i] + candidates[j] == target && i != j && i < j) {
answer.add([candidates[i], candidates[j]]);
}
}
}
}
I am sure this can be done more efficient but since the solution is for some Leetcode assignment, I don't really want to spend too much time on optimizations.
I have tried added some comments in the code which explains my way of doing it:
void main() {
getSumLists([10, 1, 2, 7, 6, 1, 5], 8).forEach(print);
// [5, 1, 2]
// [1, 6, 1]
// [1, 7]
// [6, 2]
getSumLists([2, 5, 2, 1, 2], 5).forEach(print);
// [2, 1, 2]
// [5]
}
Iterable<List<int>> getSumLists(
List<int> candidates,
int target, {
List<int>? tempAnswer,
int sum = 0,
}) sync* {
// We cannot use default value in parameter since that makes list const
final tempAnswerNullChecked = tempAnswer ?? [];
if (sum == target) {
// We got a result we can return.
// OPTIMIZATION: If you know the returned list from each found result is not
// being used between found results, you can remove the `.toList()` part.
yield tempAnswerNullChecked.toList();
} else if (sum > target) {
// No need to search further in this branch since we are over the target
return;
}
// Make a copy so we don't destroy the input list but also so it works even
// if provided list as input is non-growing / non-modifiable
final newCandidates = candidates.toList();
while (newCandidates.isNotEmpty) {
// We take numbers from the end of the list since that is more efficient.
final number = newCandidates.removeLast();
// Recursive call where we return all results we are going to find given
// the new parameters
yield* getSumLists(
newCandidates,
target,
tempAnswer: tempAnswerNullChecked..add(number),
sum: sum + number,
);
// Instead of creating a new tempAnswerNullChecked, we just reuse it and
// make sure we remove any value we are temporary adding
tempAnswerNullChecked.removeLast();
// Ensure we don't get duplicate combinations. So if we have checked the
// number `1` we remove all `1` so we don't try the second `1`.
newCandidates.removeWhere((element) => element == number);
}
}

Iterating over a complex collection in Dart

I would like to be able to iterate over this collection.
import "package:collection/collection.dart";
main() {
EqualityMap edges = new EqualityMap.from(const ListEquality(), {
[1, 'a']: [2, 3],
[2, 'a']: [2],
[3, 'b']: [4, 3],
[4, 'c']: [5]
});
}
I am doing a recursive function so this is not allowed.
edges.keys.forEach((m) {
// some more code
return something;
});
Is it possible to achieve something similar to this?
for(var edge in edges)
Something like this should work:
for (var edgeKey in edges.keys) {
var edge = edges[edgeKey];
// do something
}

Create multidimentional array in swift with different datatypes

this is my first question here so forgive me if it is not very clear.
I am trying to create an array in swift that will store either arrays of arrays or an integer number.
The array is supposed to be a simple representation of the data I will be using which is basically a tree kind of data structure like so...
Array = [ [[ [2, 3] ], [ 1, 4 ], [ 2 ]],
[ 2 ], [[2, 5], [6, 1] ], 3 ]
In overall the arrays are the branches and the integers are the leaves
I've tried declaring them as optionals like so
var test2 = [[[Int]?]?]()
Or using typedef's but I still can't get it to work.
Also, it should be possible to add new leaves to any of the arrays
Here is a solution based on enum, first declare the enum:
enum Node
{
case leaf(Int)
case branch([Node])
}
You can now write things such as:
let x = Node.leaf(42)
let y = Node.branch([Node.leaf(42), Node.leaf(24)])
However this is going to become laborious very quickly. Fortunately Swift allows conversions from literals, so we add:
extension Node : ExpressibleByIntegerLiteral
{
init(integerLiteral value: Int)
{
self = .leaf(value)
}
}
extension Node : ExpressibleByArrayLiteral
{
init(arrayLiteral elements: Node...)
{
self = .branch(elements)
}
}
And with those added we can now write the above two let statements as:
let x : Node = 42
let y : Node = [42, 24]
which is nicer. However if we print(y) we get:
branch([Node.leaf(42), Node.leaf(24)])
If you wish to pretty print that you can add:
extension Node : CustomStringConvertible
{
var description : String
{
switch self
{
case .leaf(let value):
return value.description
case .branch(let branches):
return branches.description
}
}
}
And now print(y) gives you:
[42, 24]
Finally your example:
let w : Node = [[[[2, 3]], [1, 4], [2]], [2], [[2, 5], [6, 1]], 3]
which prints as:
[[[[2, 3]], [1, 4], [2]], [2], [[2, 5], [6, 1]], 3]
You'll want to complete the enum type, with predicates such as isLeaf etc., but that is the basic idea.
HTH

Resources