How to extract items from nested lists in a dart - sorting

I was trying to write a recursive quicksort algorithm. The problem is that it returns elements in a set of nested arrays
void main(List<String> arguments) {
List myList = [2, 4, 9, 7, 1, 12];
print(quickSort(myList));
}
List quickSort(var arr){
if (arr.length < 2){
return arr;
} else {
int pivot = arr[0];
List less = [];
List greater = [];
arr.removeAt(0);
arr.forEach((element) {
if (element > pivot){
greater.add(element);
} else {
less.add(element);
}
});
return [quickSort(less), pivot, quickSort(greater)];
}
}
Here is the result of the algorithm
[[1], 2, [[], 4, [[7], 9, [12]]]]
I want to get the data in this format:
[1, 2, 4, 7, 9, 12]

There are one problem which are the main reason for your problems. But there are also multiple related problems when is the reason why you did not discover the main problem.
The main problem is that you are inserting lists instead of the content of the returned lists in:
return [quickSort(less), pivot, quickSort(greater)];
What you want here is to insert all elements from the returned list from of e.g. quickSort(less). Instead, you are inserting it as a List itself which makes your import like you are seeing it.
To fix this, you should use ... to tell Dart that it should iterate over the list and insert all the elements. So something like this:
return [...quickSort(less), pivot, ...quickSort(greater)];
The reason why you got this problem is because of missing types in general in your code. You should, in general, never just write List since that means List<dynamic> in Dart. dynamic means whatever type so the List are allowed to contain a mix of types. This is bad since that also means extracting data from these List are also going to be dynamic and Dart can therefore not help us preventing type issues.
I have rewritten your code to make it more type safe here:
void main(List<String> arguments) {
List<int> myList = [2, 4, 9, 7, 1, 12];
print(quickSort(myList));
}
List<int> quickSort(List<int> arr) {
if (arr.length < 2) {
return arr;
} else {
int pivot = arr[0];
List<int> less = [];
List<int> greater = [];
arr.removeAt(0);
for (final element in arr) {
if (element > pivot) {
greater.add(element);
} else {
less.add(element);
}
}
return [...quickSort(less), pivot, ...quickSort(greater)];
}
}
Also, I would suggest not using .forEach() but instead use normal for-each loops as I have done.
And at last, this would also be as type safe since we are allowed to use var/final to tell Dart that it should automatically figure out the correct type based on context. You should still, however, specify types when it comes to method signatures:
void main(List<String> arguments) {
final myList = [2, 4, 9, 7, 1, 12];
print(quickSort(myList));
}
List<int> quickSort(List<int> arr) {
if (arr.length < 2) {
return arr;
} else {
final pivot = arr[0];
final less = <int>[];
final greater = <int>[];
arr.removeAt(0);
for (final element in arr) {
if (element > pivot) {
greater.add(element);
} else {
less.add(element);
}
}
return [...quickSort(less), pivot, ...quickSort(greater)];
}
}
So the point is really that if you are ever going to specify types in Dart, then please write the full type since just List is much worse than final/var in most situations. :)

Related

How to efficiently add a sorted List into another sorted List?

I'm having trouble determining the most efficient way of doing this in Dart.
If have two lists that in sorted descending order,
List<int> messages = [10, 5, 4, 1];
List<int> newMessages = [5, 3, 2];
How can I add newMessages to messages so that messages now looks like
messages = [10, 5, 5, 4, 3, 2, 1];
If both lists are long, and are using the default list implementation, it might be more efficient to create a new list based on the two other lists. The reason is that inserting an element inside an existing list requires all elements after this insertion index to be moved forward. Also, when the list grows, it needs to allocate a bigger list and move all elements into this.
If we instead creates a new list, we can inform Dart what the size of this list is going to be exactly and we can prevent moving elements:
void main() {
List<int> messages = [10, 5, 4, 1];
List<int> newMessages = [5, 3, 2];
// The compare argument is given since both lists are sorted in reverse order
print(newSortedListBasedOnTwoAlreadySortedLists<int>(
messages, newMessages, (a, b) => b.compareTo(a)));
// [10, 5, 5, 4, 3, 2, 1]
}
List<E> newSortedListBasedOnTwoAlreadySortedLists<E>(
List<E> l1,
List<E> l2, [
int Function(E a, E b)? compare,
]) {
Iterator<E> i1 = l1.iterator;
Iterator<E> i2 = l2.iterator;
if (!i1.moveNext()) {
if (!i2.moveNext()) {
return [];
} else {
return l2.toList();
}
}
if (!i2.moveNext()) {
return l1.toList();
}
bool i1alive = true;
bool i2alive = true;
return List.generate(l1.length + l2.length, (_) {
if (i1alive && i2alive) {
E v1 = i1.current;
E v2 = i2.current;
int compareResult = (compare == null)
? Comparable.compare(v1 as Comparable, v2 as Comparable)
: compare(v1, v2);
if (compareResult > 0) {
i2alive = i2.moveNext();
return v2;
} else {
i1alive = i1.moveNext();
return v1;
}
} else if (i1alive) {
E v1 = i1.current;
i1alive = i1.moveNext();
return v1;
} else {
E v2 = i2.current;
i2alive = i2.moveNext();
return v2;
}
});
}
Note: The method could in theory take two Iterable as argument as long as we are sure that a call to .length does not have any negative consequences like e.g. need to iterate over the full structure (with e.g. mappings). To prevent this issue, I ended up declaring the method to take List as arguments since we know for sure that .length is not problematic here.
This sounds like you need to merge the two lists.
As stated elsewhere, it's more efficient to create a new list than to move elements around inside the existing lists.
The merge can be written fairly simply:
/// Merges two sorted lists.
///
/// The lists must be ordered in increasing order according to [compare].
///
/// Returns a new list containing the elements of both [first] and [second]
/// in increasing order according to [compare].
List<T> merge<T>(List<T> first, List<T> second, int Function(T, T) compare) {
var result = <T>[];
var i = 0;
var j = 0;
while (i < first.length && j < second.length) {
var a = first[i];
var b = second[j];
if (compare(a, b) <= 0) {
result.add(a);
i++;
} else {
result.add(b);
j++;
}
}
while (i < first.length) {
result.add(first[i++]);
}
while (j < second.length) {
result.add(second[j++]);
}
return result;
}
(In this case, the lists are descending, so they'll need a compare function which reverses the order, like (a, b) => b.compareTo(a))
You can use binary search to insert all new messages one by one in a sorted manner while maintaining efficiency.
void main() {
List<int> messages = [10, 5, 4, 1];
List<int> newMessages = [5, 3, 2];
for (final newMessage in newMessages) {
final index = binarySearchIndex(messages, newMessage);
messages.insert(index, newMessage);
}
print(messages); // [10, 5, 5, 4, 3, 2, 1]
}
int binarySearchIndex(
List<int> numList,
int value, [
int? preferredMinIndex,
int? preferredMaxIndex,
]) {
final minIndex = preferredMinIndex ?? 0;
final maxIndex = preferredMaxIndex ?? numList.length - 1;
final middleIndex = ((maxIndex - minIndex) / 2).floor() + minIndex;
final comparator = numList[middleIndex];
if (middleIndex == minIndex) {
return comparator > value ? maxIndex : minIndex;
}
return comparator > value ?
binarySearchIndex(numList, value, middleIndex, maxIndex):
binarySearchIndex(numList, value, minIndex, middleIndex);
}

Sort two lists the same way

I need to sort a list of DateTime from earliest to latest.
List<DateTime> list = [2021-01-15 12:26:40.709246, 2021-02-25 13:26:40.709246, 2021-02-20 19:26:40.709246];
datetimeList.sort();
I have another list of Strings.
List<String> list = ["one", "two", "three"];
The indexes of stringList have to match the indexes of datetimeList. So the index of "one" always has to be the same as the index of 2021-01-15 12:26:40.709246 and so on.
If I sort the lists individually, the DateTime is sorted by DateTime and the Strings are sorted alphabetically. This way, the String does not go with its initial date anymore.
How can I sort one list (datetimeList) with the other list (stringList) sorting exactly the same way?
The easiest solution would be to create a struct/class to combine both variables so you don't have to worry about keeping the objects in the arrays aligned. The last thing you need to do is to sort the array ob new objects by the date. For that, I cannot help you due to missing knowledge about Dart.
You could us a SplayTreeMap as well.https://api.dart.dev/stable/2.8.4/dart-collection/SplayTreeMap-class.html.
SplayTreeMap ensures that its keys are in sorted order.You could use your datetime as key and the its contents of other list as value.
main() {
final SplayTreeMap<DateTime, String> map =
new SplayTreeMap<DateTime, String>();
map[DateTime.parse("2021-01-15 12:26:40.709246")] = "one";
map[DateTime.parse("2021-02-25 13:26:40.709246")] = "three";
map[DateTime.parse("2021-02-20 19:26:40.709246")] = "two";
for (final DateTime key in map.keys) {
print("$key : ${map[key]}");
}
}
I recommend the simpler suggestions given here.
For completeness, I'll provide one more approach: Compute the permutation by sorting a list of indices:
List<int> sortedPermutation<T>(List<T> elements, int compare(T a, T b)) =>
[for (var i = 0; i < elements.length; i++) i]
..sort((i, j) => compare(elements[i], elements[j]));
Then you can reorder the existing lists to match:
List<T> reorder<T>(List<T> elements, List<int> permutation) =>
[for (var i = 0; i < permutation.length; i++) elements[permutation[i]]];
If you do:
var sorted = reorder(original, sortedPermutation(original, compare));
it should give you a sorted list.
It's less efficient than sorting in-place because you create a new list,
but you can apply the same reordering to multiple lists afterwards.
Fast and very effective way.
void main() {
final l1 = [3, 1, 2];
final l2 = ['three', 'one', 'two'];
final l3 = ['drei', 'ein', 'zwei'];
print(l1);
print(l2);
print(l3);
myCompare(int x, int y) => x.compareTo(y);
l1.sortLists([l2, l3], myCompare);
print('============');
print(l1);
print(l2);
print(l3);
}
extension SortListByList<E> on List<E> {
sortLists(Iterable<List> lists, int Function(E, E) compare) {
for (final list in lists) {
if (list.length != length) {
throw StateError('The length of lists must be equal');
}
}
final rules = <int>[];
sort((x, y) {
final rule = compare(x, y);
rules.add(rule);
return rule;
});
for (final list in lists) {
var rule = 0;
list.sort((x, y) => rules[rule++]);
}
}
}
Output:
[3, 1, 2]
[three, one, two]
[drei, ein, zwei]
============
[1, 2, 3]
[one, two, three]
[ein, zwei, drei]

Transform this list using linq?

I'm trying to use LINQ to transform the following list. LINQ should multiply each element against the next as long as the product is less than 15. Additionally we should save the number of elements used to form the product.
int[] values = { 1, 3, 4, 2, 7, 14 }; //assume Largest value will never be >= 15
1x3x4 = 12
2x7 = 14
14 = 14
{ {12,3}, {14,2}, {14,1} }
My ultimate goal is to take the geometric average of a very large list of numbers. This is normally done by multiplying each element in the list together (1x3x4x2x7x14) then taking the nth root (in this case 1/6).
The obvious problem in using the "normal" method is that you will quickly find yourself using numbers beyond the maximum allowable number. You can workaround this by using the old divide and conquer method and with a little help from the natural log function.
I don't think there is something like that build into standard LINQ method library. But you can easily create your own extension method. I called it AggregateUntil:
public static class EnumerableExtensions
{
public static IEnumerable<TResult> AggregateUntil<TSource, TAccumulate, TResult>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func,
Func<TAccumulate, bool> condition,
Func<TAccumulate, TResult> resultSelector
)
{
TAccumulate acc = seed;
TAccumulate newAcc;
foreach(var item in source)
{
newAcc = func(acc, item);
if(!condition(newAcc))
{
yield return resultSelector(acc);
acc = func(seed, item);
}
else
{
acc = newAcc;
}
}
yield return resultSelector(acc);
}
}
And now let's use it. First, take multiplications only, as long as they met < 15 condition:
var grouped
= values.AggregateUntil(1, (a,i) => a * i, a => a < 15, a => a).ToList();
Returns List<int> with 3 items: 12, 14, 14. That's what you need. But now lets take number of items which were aggregated into each multiplication. That's easy using anonymous type::
int[] values = { 1, 3, 4, 2, 7, 14 };
var grouped
= values.AggregateUntil(
new { v = 1, c = 0 },
(a, i) => new { v = a.v * i, c = a.c + 1 },
a => a.v < 15,
a => a).ToList(); ;
Returns exactly what you need:
My ultimate goal is to take the geometric average of a very large list of numbers.
Then just take the nth root of each number and multiply afterwards. Then you don't need to worry about splitting the list into groups:
double mean = 1.0;
foreach(int i in values)
{
mean *= Math.Pow(i, 1.0 / values.Length);
}
Which could also be done in Linq with Aggregate:
mean = values.Aggregate(1.0, (prev, i) => prev * Math.Pow(i, 1.0 / values.Length ));
Well my solution is not quite as elegant as #MarcinJuraszek, but it's fast and it works within your constraints.
int[] values = {1, 3, 4, 2, 7, 14};
int product = 1;
int elementsMultiplied = 0;
List<Tuple<int,int>> allElements = new List<Tuple<int,int>>();
for(int i = 0; i < values.Length ; i++)
{
product = product * values[i];
elementsMultiplied++;
if(i == values.Length - 1 || product * values[i+1] >= 15)
{
allElements.Add(new Tuple<int,int>(product, elementsMultiplied));
product = 1;
elementsMultiplied = 0;
}
}
foreach(Tuple<int,int> pair in allElements)
{
Console.WriteLine(pair.Item1 + "," + pair.Item2);
}

Does any built in function in VC++ to sort number?

I have two columns of data. For example,
[78, c]
[28, a]
[34, g]
I want to see whether any built-in function to sort the number and tell me the order information. For example, (from small to large) the function will return [2, 3, 1] because the 2nd row has the smallest 1st column element.
What is your data structure?
If you're in C++/CLI, then you've got the entire .NET framework available to you.
That said, I don't believe that there's anything built-in that will tell you the order. I believe everything will actually do the sort.
If you really need the order, not a sorted list, I believe this will do it. This creates new objects that remember their original list position, sorts them, and then reads back what the original indexes were.
// I'm assuming you have a class similar to this already.
ref class MyData
{
public:
int number;
String^ letter;
};
ref class SortHelper : IComparable<SortHelper^>
{
public:
MyData^ data;
int originalIndex;
SortHelper(MyData^ data, int index)
{
this->data = data;
this->originalIndex = index;
}
virtual CompareTo(SortHelper^ other)
{
return this->data->number.CompareTo(other->data->number);
}
};
void List<int> GetSortedIndexes(List<MyData>^ input)
{
List<SortHelper>^ working = gcnew List<SortHelper>();
for(int i = 0; i < input->Count; i++)
{
working->Add(gcnew SortHelper(input[i], i));
}
working->Sort();
List<int>^ result = gcnew List<int>();
for each(SortHelper^ helper in working)
{
result->Add(helper->originalIndex);
}
return result;
}

LINQ implementation of Cartesian Product with pruning

I hope someone is able to help me with what is, at least to me, quite a tricky algorithm.
The Problem
I have a List (1 <= size <= 5, but size unknown until run-time) of Lists (1 <= size <= 2) that I need to combine. Here is an example of what I am looking at:-
ListOfLists = { {1}, {2,3}, {2,3}, {4}, {2,3} }
So, there are 2 stages to what I need to do:-
(1). I need to combine the inner lists in such a way that any combination has exactly ONE item from each list, that is, the possible combinations in the result set here would be:-
1,2,2,4,2
1,2,2,4,3
1,2,3,4,2
1,2,3,4,3
1,3,2,4,2
1,3,2,4,3
1,3,3,4,2
1,3,3,4,3
The Cartesian Product takes care of this, so stage 1 is done.....now, here comes the twist which I can't figure out - at least I can't figure out a LINQ way of doing it (I am still a LINQ noob).
(2). I now need to filter out any duplicate results from this Cartesian Product. A duplicate in this case constitutes any line in the result set with the same quantity of each distinct list element as another line, that is,
1,2,2,4,3 is the "same" as 1,3,2,4,2
because each distinct item within the first list occurs the same number of times in both lists (1 occurs once in each list, 2 appears twice in each list, ....
The final result set should therefore look like this...
1,2,2,4,2
1,2,2,4,3
--
1,2,3,4,3
--
--
--
1,3,3,4,3
Another example is the worst-case scenario (from a combination point of view) where the ListOfLists is {{2,3}, {2,3}, {2,3}, {2,3}, {2,3}}, i.e. a list containing inner lists of the maximum size - in this case there would obviously be 32 results in the Cartesian Product result-set, but the pruned result-set that I am trying to get at would just be:-
2,2,2,2,2
2,2,2,2,3 <-- all other results with four 2's and one 3 (in any order) are suppressed
2,2,2,3,3 <-- all other results with three 2's and two 3's are suppressed, etc
2,2,3,3,3
2,3,3,3,3
3,3,3,3,3
To any mathematically-minded folks out there - I hope you can help. I have actually got a working solution to part 2, but it is a total hack and is computationally-intensive, and I am looking for guidance in finding a more elegant, and efficient LINQ solution to the issue of pruning.
Thanks for reading.
pip
Some resources used so far (to get the Cartesian Product)
computing-a-cartesian-product-with-linq
c-permutation-of-an-array-of-arraylists
msdn
UPDATE - The Solution
Apologies for not posting this sooner...see below
You should implement your own IEqualityComparer<IEnumerable<int>> and then use that in Distinct().
The choice of hash code in the IEqualityComparer depends on your actual data, but I think something like this should be adequate if your actual data resemble those in your examples:
class UnorderedQeuenceComparer : IEqualityComparer<IEnumerable<int>>
{
public bool Equals(IEnumerable<int> x, IEnumerable<int> y)
{
return x.OrderBy(i => i).SequenceEqual(y.OrderBy(i => i));
}
public int GetHashCode(IEnumerable<int> obj)
{
return obj.Sum(i => i * i);
}
}
The important part is that GetHashCode() should be O(N), sorting would be too slow.
void Main()
{
var query = from a in new int[] { 1 }
from b in new int[] { 2, 3 }
from c in new int[] { 2, 3 }
from d in new int[] { 4 }
from e in new int[] { 2, 3 }
select new int[] { a, b, c, d, e };
query.Distinct(new ArrayComparer());
//.Dump();
}
public class ArrayComparer : IEqualityComparer<int[]>
{
public bool Equals(int[] x, int[] y)
{
if (x == null || y == null)
return false;
return x.OrderBy(i => i).SequenceEqual<int>(y.OrderBy(i => i));
}
public int GetHashCode(int[] obj)
{
if ( obj == null || obj.Length == 0)
return 0;
var hashcode = obj[0];
for (int i = 1; i < obj.Length; i++)
{
hashcode ^= obj[i];
}
return hashcode;
}
}
The finalised solution to the whole combining of multisets, then pruning the result-sets to remove duplicates problem ended up in a helper class as a static method. It takes svick's much appreciated answer and injects the IEqualityComparer dependency into the existing CartesianProduct answer I found at Eric Lipperts's blog here (I'd recommend reading his post as it explains the iterations in his thinking and why the linq implimentation is the best).
static IEnumerable<IEnumerable<T>> CartesianProduct<T>(IEnumerable<IEnumerable<T>> sequences,
IEqualityComparer<IEnumerable<T>> sequenceComparer)
{
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
var resultsSet = sequences.Aggregate(emptyProduct, (accumulator, sequence) => from accseq in accumulator
from item in sequence
select accseq.Concat(new[] { item }));
if (sequenceComparer != null)
return resultsSet.Distinct(sequenceComparer);
else
return resultsSet;
}

Resources