Dart type castings - dart

I try to implement mergeSort in dart. Here is my code:
List mergeSort(List list)
{
if (list.length <= 1) return list;
List left, right, result;
int middle = list.length ~/ 2;
left = mergeSort(list.getRange(0, middle));
right = mergeSort(list.getRange(middle, list.length) as List);
result = merge(left, right);
return result;
}
And I get an TypeError at this line:
left = mergeSort(list.getRange(0, middle));
It seems that getRange() returns Iterable, but List implements Iterable what is the problem here, shouldn't it work?
Anyway when I try:
left = mergeSort(list.getRange(0, middle) as List);
it still doesn't work and gives me a CastError.
So my question is what's the problem here, and what's the Dart-style solution for it?
Thx in advance.

Iterable.toList() should do the trick.
left = mergeSort(list.getRange(0, middle).toList());
You can't directly cast an Iterable to a List because Iterable is a super type of List.
You can cast an object to its parent class, but you cant cast an object to any of its child class.
Example:
var a = new AnyClass();
var o = new Object(); //Actually this is not correct, but let's imagine
(o as AnyClass).toString() //wont works
(a as Object).toString() //will works

The getRange method returns an Iterable, not a List. Using as List does not change that, it just fails because its operand isn't actually a List.
You can use the List.sublist method to get a slice of a list as an actual List.
The collection package on pub also contains an implementation of merge-sort: package:collection/algorithms.dart.

Related

Generic method that returns List<T> instead returns List<dynamic>

I tried writing a simple generic method that would iteratively copy a nested List, for example a List<List<int>>. But unfortunately, the recursive call seems to always return List<dynamic>, so I get the following error
The argument type List<dynamic> can't be assigned to the parameter type T
List<T> listDeepCopy<T>(List<T> list){
List<T> newList = List<T>();
list.forEach((value) {
if( value is List ){
newList.add(listDeepCopy(value)); // <-- listDeepCopy() always returns List<dynamic>
}
else{
newList.add(value);
}
});
return newList;
}
So if I call
List<List<int>> list = [[1,2],[3,4]];
List<List<int>> copy = listDeepCopy(list);
T is List<int>
value is T - i.e. List<int>
listDeepCopy(value) should equal listDeepCopy<List<int>>, which would return a List<int>, which should be possible to add to newList, which is a List<List<int>>
Where am I going wrong here, and how can I make something like this work?
I probably would implement it as:
List<T> listDeepCopy<T>(List<T> list) {
var copy = list.toList();
for (var i = 0; i < copy.length; i += 1) {
var element = copy[i];
if (element is List) {
copy[i] = listDeepCopy(element) as T;
}
}
return copy;
}
void main() {
List<List<int>> list = [
[1, 2],
[3, 4]
];
List<List<int>> copy = listDeepCopy(list);
list[0][0] = 99;
print(copy); // Prints: [[1, 2], [3, 4]]
}
A problem with your approach is that Dart cannot properly infer the generic type parameter for that recursive listDeepCopy(value) call. value is of type T that is known to be a List (which is shorthand for List<dynamic>), and I am not aware of a way to extract the static element type. (Maybe #lrn will see this and provide a better, more complete explanation.)
In such a case, it's better to rely on polymorphism by calling a method on the List that returns a copy of itself: .toList().
(As an example where this matters, consider a shallow copy scenario:
List<T> shallowCopy1<T>(List<T> list) => <T>[...list];
List<T> shallowCopy2<T>(List<T> list) => list.toList();
extension StaticType<T> on T {
Type get staticType => T;
}
void main() {
List<num> list = <int>[1, 2, 3];
var copy1 = shallowCopy1(list);
var copy2 = shallowCopy2(list);
print('original: staticType: ${list.staticType}, runtimeType: ${list.runtimeType}');
print('copy1: staticType: ${copy1.staticType}, runtimeType: ${copy1.runtimeType}');
print('copy2: staticType: ${copy2.staticType}, runtimeType: ${copy2.runtimeType}');
}
Although both copies preserve the static type of the original List, only copy2 preserves the object's actual (runtime) type. A proper copy depends on the runtime type of the object being copied, and the only robust way to do that is for the object to create a copy of itself.)
You can't do it the way you are trying to do it.
The problem is that deepClone<T> converts a List<dynamic> to a List<T> (which is fine) and then tries to convert elements that are themselves lists into typed list ... but you don't know the type.
In effect, when you check that value is List, you don't know what kind of list to convert it to.
There are two cases:
Either T is List<X> or Iterable<X> for some type X, but you have no way to get your hands on that X. Dart doesn't allow you to destructure types at runtime.
Or T is Object or another general supertype with no "list element" type inside it, and then you simply do not have any information about what List type to convert the nested list to. (That's actually the simplest case, because then you should simply not deepClone the list at all).
There is a way to figure out which case you are in (<T>[] is List<Iterable<Object?>>), but it won't help you in the former case, unless you want to do an exhaustive search of all the possible types that X might be.
What I'd do instead is to build a converter, instead of using a single function.
abstract class Cloner<T> {
const factory Cloner() = _ValueCloner<T>;
T clone(dynamic source);
Cloner<List<T>> get list => _ListCloner(this);
}
abstract class _BaseCloner<T> implements Cloner<T> {
const _BaseCloner();
Cloner<List<T>> get list => _ListCloner<T>(this);
}
class _ValueCloner<T> extends _BaseCloner<T> {
const _ValueCloner();
T clone(dynamic source) => source as T;
}
class _ListCloner<T> extends _BaseCloner<List<T>> {
final Cloner<T> _base;
_ListCloner(this._base);
List<T> clone(dynamic source) =>
<T>[for (var o in source as List<dynamic>) _base.clone(o)];
}
Then, if you actually know the type of the data, you can build your cloner as:
var typedList =
Cloner<int>().list.list.clone(
<dynamic>[<dynamic>[1, 2], <dynamic>[3, 4]]);
which yields a List<List<int>> with the value <List<int>>[<int>[1, 2], <int>[3, 4]].

Applying the `collec()` of stream for counting. Exercise

I am trying to create a custom collector in order to count valid elements of a list. I have done it using one of the already provide collectors:
arr.stream()
.filter(e -> e.matches("[:;][~-]?[)D]"))
.map(e -> 1)
.reduce(0, Integer::sum);
but as a challenge for myself, I wanted to create my own custom collector in order to understand it better. And this is where I got stuck.
It is probably something trivial but I am learning this and can't figure a supplier, an accumulator, and a combiner. I guess I still don't understand something about them. For instance, I have a similar stream:
arr1.stream()
.filter(e -> e.matches("[:;][~-]?[)D]"))
.map(e -> 1)
.collect(temporary array, adding to array, reduce);
AFAIK supplier is a function without arguments, which returns something. I studied standard examples and it is usually a method reference for a new collection, e.g. ArrayList::new. I tried to use constant 0, e -> 0 because I want to return a scalar. I think it is wrong because it makes the stream returning 0. If using method reference for a temporary collection, Java complains about a mismatch of types of a supplier and returning object. I am also confused about using an accumulator if the final result is a number as a combiner would reduce all elements to a number, e.g. (a,b) -> a + b`.
I'm completely stumped.
Probably part of your problem is that you cannot obviously create an accumulator for an Integer type since it is immutable.
You start with this:
System.out.println(IntStream.of(1,2,3).reduce(0, Integer::sum));
You can extend to this:
System.out.println(IntStream.of(1,2,3).boxed()
.collect(Collectors.reducing(0, (i1,i2)->i1+i2)));
Or even this, which has an intermediate mapping function
System.out.println(IntStream.of(1,2,3).boxed()
.collect(Collectors.reducing(0, i->i*2, (i1,i2)->i1+i2)));
You can get this far with your own Collector
Collector<Integer, Integer, Integer> myctry = Collector.of(
()->0,
(i1,i2)->{
// what to do here?
},
(i1,i2)->{
return i1+i2;
}
);
The accumulator is A function that folds a value into a mutable result container with mutable being the keyword here.
So, make a mutable integer
public class MutableInteger {
private int value;
public MutableInteger(int value) {
this.value = value;
}
public void set(int value) {
this.value = value;
}
public int intValue() {
return value;
}
}
And now:
Collector<MutableInteger, MutableInteger, MutableInteger> myc = Collector.of(
()->new MutableInteger(0),
(i1,i2)->{
i1.set(i1.intValue()+i2.intValue());
},
(i1,i2)->{
i1.set(i1.intValue()+i2.intValue());
return i1;
}
);
And then:
System.out.println(IntStream.of(1,2,3)
.mapToObj(MutableInteger::new)
.collect(myc).intValue());
Reference:
Example of stream reduction with distinct combiner and accumulator
EDIT: The finisher just does whatever with the final result. If you don't set it on purpose then it is set by default to IDENTITY_FINISH which is Function.identity() which says just to return the final result as is.
EDIT: If you're really desperate:
Collector<int[], int[], int[]> mycai = Collector.of(
()->new int[1],
(i1,i2)->i1[0] += i2[0],
(i1,i2)->{i1[0] += i2[0]; return i1;}
);
System.out.println(IntStream.of(1,2,3)
.mapToObj(v->{
int[] i = new int[1];
i[0] = v;
return i;
})
.collect(mycai)[0]);

Is it possible to make a TreeMap from a Map literal?

I have a Map literal, an I want it to be a TreeMap, but by default I believe it's a LinkedHashMap. Casting a LinkedHashMap to a TreeMap won't work as it's not a subtype.
Basically, I'm looking for the simplest way to make this work:
var map = <int, int>{for(int i = 0; i < intervals.length; i++) intervals[i][0] : i} as SplayTreeMap;
As mentioned before, casting as SplayTreeMap won't work as they types don't align.
Thanks much in advance
Use the SplayTreeMap.from constructor to create a SplayTreeMap. There isn't any way to cast it as you said.
Remove the as from your current code and add this to get your SplayTreeMap:
var newMap = SplayTreeMap.from(map);
Depending on your key type and your use case, you can pass compare and isValidKey parameters as well. Full constructor definition:
SplayTreeMap<K, V>.from(
Map other,
[int compare(
K key1,
K key2
),
bool isValidKey(
dynamic potentialKey
)]
)

Searching a List of objects for a particular object in dart using "where"

I would like to obtain an object from a List based on a specific search criteria of its member variable
this is the code I am using
class foo
{
foo(this._a);
int _a;
}
List<foo> lst = new List<foo>();
main()
{
foo f = new foo(12);
lst.add(f);
List<foo> result = lst.where( (foo m) {
return m._a == 12;
});
print(result[0]._a);
}
I am getting the error and not sure how to resolve this
Uncaught exception:
TypeError: Instance of 'WhereIterable<foo>': type 'WhereIterable<foo>' is not a subtype of type 'List<foo>'
I am trying to search for an object whose member variable a == 12. Any suggestions on what I might be doing wrong ?
The Iterable.where method returns an iterable of all the members which satisfy your test, not just one, and it's a lazily computed iterable, not a list. You can use lst.where(test).toList() to create a list, but that's overkill if you only need the first element.
You can use lst.firstWhere(test) instead to only return the first element, or you can use lst.where(test).first to do effectively the same thing.
In either case, the code will throw if there is no element matched by the test.
To avoid throwing, you can use var result = lst.firstWhere(test, orElse: () => null) so you get null if there is no such element.
Another alternative is
foo result;
int index = lst.indexWhere(test);
if (index >= 0) result = lst[index];
The answer is simple. Iterable.where returns an Iterable, not a List. AFAIK this is because _WhereIterable does its computations lazily.
If you really need to return a List, call lst.where(...).toList().
Otherwise, you can set result to be an Iterable<foo>, instead of a List<foo>.
or you can go crazy and do this:
bool checkIfProductNotFound(Map<String, Object> trendingProduct) {
bool isNotFound = this
._MyProductList
.where((element) => element["id"] == trendingProduct["id"])
.toList()
.isEmpty;
return isNotFound ;
}

Easiest way to convert a string into a HashMap

if I have some text in a String like:
"abc=123,def=456,ghi=789"
how could I create a populated HashMap<String,Int> object for it in the easiest, shortest amount of code possible in Kotlin?
I can think of no solution easier than this:
val s = "abc=123,def=456,ghi=789"
val map = s.split(",").associate {
val (left, right) = it.split("=")
left to right.toInt()
}
Or, if you need exactly a HashMap, use .associateTo(HashMap()) { ... }.
Some details:
.associate { ... } receives a function that produces pairs which are then stored into a map as keys and values respectively.
val (left, right) = it.split("=") is the usage of destructuring declarations on the list returned from it.split("="), it takes the first two items from the list.
left to right.toInt() creates a Pair<String, Int> defining a single mapping.
You can map each key/value to a Pair with the to keyword. An iterable of Pair can be mapped to a Map easily with the toMap() extension method.
val s = "abc=123,def=456,ghi=789"
val output = s.split(",")
.map { it.split("=") }
.map { it.first() to it.last().toInt() }
.toMap()

Resources