Dart List min/max value - dart

How do you get the min and max values of a List in Dart.
[1, 2, 3, 4, 5].min //returns 1
[1, 2, 3, 4, 5].max //returns 5
I'm sure I could a) write a short function or b) copy then sort the list and select the last value,
but I'm looking to see if there is a more native solution if there is any.

Assuming the list is not empty you can use Iterable.reduce :
import 'dart:math';
main(){
print([1,2,8,6].reduce(max)); // 8
print([1,2,8,6].reduce(min)); // 1
}

If you don't want to import dart: math and still wants to use reduce:
main() {
List list = [2,8,1,6]; // List should not be empty.
print(list.reduce((curr, next) => curr > next? curr: next)); // 8 --> Max
print(list.reduce((curr, next) => curr < next? curr: next)); // 1 --> Min
}

You can now achieve this with an extension as of Dart 2.6:
import 'dart:math';
void main() {
[1, 2, 3, 4, 5].min; // returns 1
[1, 2, 3, 4, 5].max; // returns 5
}
extension FancyIterable on Iterable<int> {
int get max => reduce(math.max);
int get min => reduce(math.min);
}

An example to get Min/Max value using reduce based on condition for a list of Map objects
Map studentA = {
'Name': 'John',
'Marks': 85
};
Map studentB = {
'Name': 'Peter',
'Marks': 70
};
List<Map> students = [studentA, studentB];
// Get student having maximum mark from the list
Map studentWithMaxMarks = students.reduce((a, b) {
if (a["Marks"] > b["Marks"])
return a;
else
return b;
});
// Get student having minimum mark from the list (one liner)
Map studentWithMinMarks = students.reduce((a, b) => a["Marks"] < b["Marks"] ? a : b);
Another example to get Min/Max value using reduce based on condition for a list of class objects
class Student {
final String Name;
final int Marks;
Student(this.Name, this.Marks);
}
final studentA = Student('John', 85);
final studentB = Student('Peter', 70);
List<Student> students = [studentA, studentB];
// Get student having minimum marks from the list
Student studentWithMinMarks = students.reduce((a, b) => a.Marks < b.Marks ? a : b);

If your list is empty, reduce will throw an error.
You can use fold instead of reduce.
// nan compare to any number will return false
final initialValue = number.nan;
// max
values.fold(initialValue, (previousValue, element) => element.value > previousValue ? element.value : previousValue);
// min
values.fold(initialValue, (previousValue, element) => element.value < previousValue ? element.value : previousValue);
It can also use to calculate sum.
final initialValue = 0;
values.fold(initialValue, (previousValue, element) => element.value + previousValue);
Although fold is not cleaner than reduce for getting min/max, it is still a powerful method to do more flexible actions.

For empty lists: This will return 0 if list is empty, the max value otherwise.
List<int> x = [ ];
print(x.isEmpty ? 0 : x.reduce(max)); //prints 0
List<int> x = [1,32,5];
print(x.isEmpty ? 0 : x.reduce(max)); //prints 32

int minF() {
final mass = [1, 2, 0, 3, 5];
mass.sort();
return mass[0];
}

void main() {
firstNonConsecutive([1,2,3,4,6,7,8]);
}
int? firstNonConsecutive(List<int> arr) {
var max = arr.reduce((curr, next) => curr > next? curr: next);
print(max); // 8 --> Max
var min = arr.reduce((curr, next) => curr < next? curr: next);
print(min); // 1 --> Min
return null;
}

If you need a more sophisticated min/max, such as finding an object with a min/max of a field, or use of a comparison predicate, use minBy() and maxBy() from the collection package:
import 'package:collection/collection.dart';
class Person {
final String name;
final int age;
Person(this.name, this.age);
#override
String toString() => '$name (age $age)';
}
main() {
final alice = Person('Alice', 30);
final bob = Person('Bob', 40);
final chris = Person('Chris', 25);
final dan = Person('Dan', 35);
final people = [alice, bob, chris, dan];
print('Youngest is ${minBy(people, (e) => e.age)}');
print('Oldest is ${maxBy(people, (e) => e.age)}');
print('First alphabetically is ${minBy(people, (e) => e.name)}');
print('Last alphabetically is ${maxBy(people, (e) => e.name)}');
print('Largest name length times age is ${maxBy(people, (e) => e, compare: (a, b) => (a.name.length * a.age).compareTo(b.name.length * b.age))}');
}
Output:
Youngest is Chris (age 25)
Oldest is Bob (age 40)
First alphabetically is Alice (age 30)
Last alphabetically is Dan (age 35)
Largest name length times age is Alice (age 30)```

Related

Check if element is the last value in fold function

I am using fold on an array which hasn't been assign to a variable and want to check whether the element is the last value. With a conventional for loop I can do this:
List<int> ints = [1, 2, 3];
int sum = 0;
for (int num in ints]) {
if (num != ints.last) {
sum = sum + num;
}
}
print(sum);
Is it possible to do this with fold instead?
int foldSum = [1, 2, 3].fold(0, (int prev, element) => prev + element);
print(foldSum);
I can't find any way of check when fold is at the last value. Note: this is a simplified example of my problem and the reason the list isn't assigned to a variable (allowing me to use .last) is because it is the result of a call to .map().
For completeness, below is the actual code (which won't obviously won't be runnable in isolation but will help illustrate my problem) I am trying to convert to use .map and .fold:
String get fieldsToSqlInsert {
String val = "";
for (Column column in columns) {
if (data.containsKey(column.name)) {
val = '$val "${data[column.name]}"';
} else {
val = "$val NULL";
}
if (column != columns.last) {
val = "$val,";
}
}
return val;
}
But it doesn't work because I don't know how to check when fold is at the final element:
String get fieldsToSqlInsert => columns
.map((column) =>
data.containsKey(column.name) ? data[column.name] : "NULL")
.fold("", (val, column) => column != columns.last ? "$val," : val);
If you simply want to exclude the last element from further calculation, you can just use take to do so:
String get fieldsToSqlInsert => columns.take(columns.length - 1)...

How to find all subsets of a set in Dart?

I need to get all possible subsets of an array.
Say I have this:
<int>[1, 2, 3]
How do I get this?
[], [1], [2], [3],[1, 2], [2, 3], [1, 3], [1, 2, 3]
I am interested in all subsets. For subsets of specific length, refer to the following questions:
How to find all subsets of a set in JavaScript?
Here is my take on it, with only native function as in your link:
List getAllSubsets(List l) => l.fold<List>([[]], (subLists, element) {
return subLists
.map((subList) => [
subList,
subList + [element]
])
.expand((element) => element)
.toList();
});
If you want a specific size:
List getSizedSubsets(List l, int size) =>
getAllSubsets(l).where((element) => element.length == size).toList();
I'd probably go with something simple like:
Iterable<Set<E>> subsets<E>(Set<E> elements) sync* {
if (elements.length >= 32) {
// Otherwise there'll be more than 2^32 subsets. And bitops will overflow in JS.
throw ArgumentError.value(elements, "elements", "must have less than 32 elements");
}
var list = [...elements];
var subsetCount = 1 << list.length;
for (var i = 0; i < subsetCount; i++) {
yield {
for (var j = 0, bit = 1; j < elements.length; j++, bit <<= 1)
if (i & bit != 0) list[j]
};
}
}
Another approach is to only have one set, and then update it iteratively to contain different elements. It's possible to go through all the sets doing only single-element changes on each step (using Gray-code):
/// Iterates a set through all combinations of its elements.
///
/// Adds and removes elements from [set] to make it iterate through all
/// possible combinations of its initial elements.
/// The current value of the iterator is always [set].
/// If iterated through to the end, the [set] ends up with all its original elements.
Iterable<Set<E>> subsets<E>(Set<E> set) sync* {
if (set.length >= 32) {
throw ArgumentError.value(set, "set", "must have less than 32 elements");
}
var list = [...set];
var prev = 0;
var counter = 0;
do {
yield set;
var next = ++counter ^ (counter >> 1);
var bit = prev ^ next; // One bit set.
var index = bit.bitLength - 1;
if (index >= list.length) index = 0;
var element = list[index];
if (next & bit == 0) {
set.add(element);
} else {
set.remove(element);
}
prev = next;
} while (set.length < list.length);
}

Dart - get the nearest(larger) value from List?

How can I find the closest value in a list, which will return me the higher value?
Example: List of [3,7,12,19] if my value is 8 how can I get the nearest(larger) value 12? i want this logic in dart.
Just filter the List only for the values higher or equal to your number and get the lowest value:
var n = 8; // Number to match
var l = [3, 7, 12, 19]; // List of values
var greater = l.where((e) => e >= n).toList()..sort(); //List of the greater values
print(greater.first); // Print the first value. -> 12
To get Closest Value of number
import 'dart:math';
import 'dart:collection';
void main(){
List<double> value = [1,4,6,3,7,9,12,34,12,-12,-91];
print(value.getCloseValue(8)); // 7
print(value.getCloseValue(6)); // 6
print(value.getCloseValue(-11)); // -12
}
extension on List<num> {
num getCloseValue(num x) {
if (isEmpty) return 0;
Map<num, num> values = {};
forEach((e) {
values[e] = (e - x).abs();
});
var sortedKeys = values.keys.toList(growable:false)
..sort((k1, k2) => values[k1]!.compareTo(values[k2]!));
final sortedMap = LinkedHashMap
.fromIterable(sortedKeys, key: (k) => k, value: (k) => values[k]);
return sortedMap.keys.first;
}
}
List<int> arr = [6, 12, 11, 18, 24,5,6,99,10,9];
arr.sort((a, b) => a.compareTo(b));
print(arr);
print(Utils.getNextLargerNumber(8, arr));
and below is the logic:
static int getNextLargerNumber(int number, List<int> array)
{
for (var i = 0; i < array.length; i++) {
if (number < array[i]) {
return array[i];
}
}
return -1;
}
Mattia's answer is already good enough. (although the list cant have the length 0 and it might be not as efficient, as you have a where() as well as sort() in there). Here is a different approach, that solves those concerns:
Nearest value to target (larger favored)
final nearestLarger = list.isEmpty ? null : list.reduce(
(a, b) => (a-target).abs() < (b -target).abs() ? a : b);
Nearest value to target (smaller favoured)
final nearestSmaller = list.isEmpty ? null : list.reduce(
(a, b) => (a-target).abs() <= (b -target).abs() ? a : b);
Note that both functions retrieve the nearest value to the target, but in case of ambiguity (eg. [3,4,5]) either the bigger or smaller value is favored.

Resample and normalize series with Deedle

I have input of raw feed from several sources that don't produce values at static rates and need to resample and normalize it for further processing.
Values are resampled to 500ms using average to aggregate multiple values.
Then forward fill is applied to fill missing values with last value and back fill to fill possible missing values in the beginning of data.
#raw feed
time value source
09:30:00.230 2 B
09:30:00.417 3 B
09:30:00.417 1 A
09:30:00.653 3 A
09:30:01.450 2 B
09:30:01.887 5 A
09:30:02.653 5 B
09:30:02.763 3 B
09:30:02.967 5 B
09:30:03.107 6 A
09:30:03.670 6 B
#resampled to 500ms intervals using average
time A B
09:30:00.000 NULL 2
09:30:00.500 2 3
09:30:01.000 NULL NULL
09:30:01.500 NULL 2
09:30:02.000 5 NULL
09:30:02.500 NULL 5
09:30:03.000 6 4
09:30:03.500 NULL 6
#ffill+bfill
time A B
09:30:00.000 2 2
09:30:00.500 2 3
09:30:01.000 2 3
09:30:01.500 2 2
09:30:02.000 5 2
09:30:02.500 5 5
09:30:03.000 6 4
09:30:03.500 6 6
I used following code, but I doubt it is efficient way to use Deedle and resulting dataframe contains duplicate values due to full outer join, so now I need so way to aggregate them or split them to series and resample them again?
Please advise if there's a better way to meet the requirements.
private void Resample(IList<(DateTime time, double value, string source)> rawSource)
{
var sourceASeries = rawSource.Where(x => x.source.ToLowerInvariant() == "A").Select(x => KeyValue.Create(x.time, x.value)).ToSeries();
var sourceBSeries = rawSource.Where(x => x.source.ToLowerInvariant() == "B").Select(x => KeyValue.Create(x.time, x.value)).ToSeries();
var sourceAResampled = sourceASeries.ResampleUniform(dt => dt.RoundMs(500), dt => dt.RoundMs(500).AddMilliseconds(500),
Lookup.ExactOrSmaller);
var sourceBResampled = sourceBSeries.ResampleUniform(dt => dt.RoundMs(500), dt => dt.RoundMs(500).AddMilliseconds(500),
Lookup.ExactOrSmaller);
var df = Frame.FromColumns(new[] { sourceAResampled, sourceBResampled });
df = df.FillMissing(Direction.Forward).FillMissing(Direction.Backward);
}
In Python using Pandas it works fine for me using following code:
import Bs as pd
A_vals = vals.where(vals['Source']==' A', inplace=False).rename(columns={"Value":" A"}).drop(['Source'], axis=1)
B_vals = vals.where(vals['Source']=='B', inplace=False).rename(columns={"Value":"B"}).drop(['Source'], axis=1)
A_vals= A_vals.resample('100ms').mean().ffill().bfill()
B_vals=B_vals.resample('100ms').mean().ffill().bfill()
result=pd.concat([ A_vals,B_vals], axis=1)
I managed to get correct results using following code, though I'm sure it can be optimized performance wise:
private IList<(int rownum, DateTime time, double A, double B)> ResampleAndNormalize(IList<(DateTime time, double value, string source)> rawTicks, int interval = 100)
{
var uniqueTicks = rawTicks.GroupBy(x => (time: x.time, source: x.source), x => x,
(k, ticks) => (time: k.time, value: ticks.Average(x => x.value), source: k.source)).ToList();
var ASeries = uniqueTicks.Where(x => x.source.ToLowerInvariant() == "A").Select(x => KeyValue.Create(x.time, x.value)).ToSeries();
var BSeries = uniqueTicks.Where(x => x.source.ToLowerInvariant() == "B").Select(x => KeyValue.Create(x.time, x.value)).ToSeries();
var startTime = ASeries.FirstKey().MinTime(BSeries.FirstKey()).RoundMs(interval);
var endTime = ASeries.LastKey().MaxTime(BSeries.LastKey()).RoundMs(interval);
var newKeys = Enumerable.Range(0, (int)Math.Ceiling(endTime.Subtract(startTime).TotalMilliseconds / interval))
.Select(x => startTime.AddMilliseconds(x * interval)).ToList();
var AResampled = ASeries.ResampleEquivalence(x => x.RoundMs(interval), x => x.Mean());
var BResampled = BSeries.ResampleEquivalence(x => x.RoundMs(interval), x => x.Mean());
AResampled = AResampled.Realign(newKeys).FillMissing(Direction.Forward).FillMissing(Direction.Backward);
BResampled = BResampled.Realign(newKeys).FillMissing(Direction.Forward).FillMissing(Direction.Backward);
var results = new List<(int rownum, DateTime time, double A, double B)>();
for (int i = 0; i < newKeys.Count; i++)
{
var time = newKeys[i];
var Avalue = AResampled.GetAt(i);
var Bvalue = BResampled.GetAt(i);
results.Add((rownum: 0, time: time, A: Avalue, B: Bvalue));
}
return results;
}
public static class DateTimeExtensions
{
public static DateTime RoundMs(this DateTime time, int precision)
{
var ticksPrecision = precision * TimeSpan.TicksPerMillisecond;
var ticksRemainder = time.Ticks % ticksPrecision;
if (ticksRemainder >= ticksPrecision / 2)
ticksRemainder = ticksPrecision - ticksRemainder;
else
ticksRemainder = -ticksRemainder;
return time.AddTicks(ticksRemainder);
}
public static DateTime MinTime(this DateTime a, DateTime b)
{
return a >= b ? b : a;
}
public static DateTime MaxTime(this DateTime a, DateTime b)
{
return a < b ? b : a;
}
}

Rotate/Shift a list in Dartlang?

Is there a better/faster way in Dart to rotate a list?
List<Object> rotate(List<Object> l, int i) {
i = i % l.length;
List<Object> x = l.sublist(i);
x.addAll(l.sublist(0, i));
return x;
}
Could be simplified a bit
List<Object> rotate(List<Object> list, int v) {
if(list == null || list.isEmpty) return list;
var i = v % list.length;
return list.sublist(i)..addAll(list.sublist(0, i));
}
If you want to shift instead of rotate you can simply use the removeAt function:
List<int> list = [ 1, 2, 3 ];
int firstElement = list.removeAt(0);
print(list); // [ 2, 3 ]
print(firstElement); // 1
From the docs:
Removes the object at position [index] from this list.
This method reduces the length of this by one and moves all later objects down by one position.
Returns the removed value.
The [index] must be in the range 0 ≤ index < length. The list must be growable.
Here are some more useful JS shims.

Resources