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

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]);

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]].

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 ;
}

search in maps dart2 , same as list.indexOf?

I Use this sample for search in Map but not work :|:
var xmenList = ['4','xmen','4xmen','test'];
var xmenObj = {
'first': '4',
'second': 'xmen',
'fifth': '4xmen',
'author': 'test'
};
print(xmenList.indexOf('4xmen')); // 2
print(xmenObj.indexOf('4xmen')); // ?
but I have error TypeError: xmenObj.indexOf$1 is not a function on last code line.
Pelease help me to search in map object simple way same as indexOf.
I found the answer:
print(xmenObj.values.toList().indexOf('4xmen')); // 2
or this:
var ind = xmenObj.values.toList().indexOf('4xmen') ;
print(xmenObj.keys.toList()[ind]); // fifth
Maps are not indexable by integers, so there is no operation corresponding to indexOf. If you see lists as specialized maps where the keys are always consecutive integers, then the corresponding operation should find the key for a given value.
Maps are not built for that, so iterating through all the keys and values is the only way to get that result.
I'd do that as:
K keyForValue<K, V>(Map<K, V> map, V value) {
for (var entry in map.entries) {
if (entry.value == value) return key;
}
return null;
}
The entries getter is introduced in Dart 2. If you don't have that, then using the map.values.toList().indexOf(value) to get the iteration position, and then map.keys.elementAt(thatIndex) to get the corresponding key.
If you really only want the numerical index, then you can skip that last step.
It's not amazingly efficient (you allocate a new list and copy all the values). Another approach is:
int indexOfValue<V>(Map<Object, V> map, V value) {
int i = 0;
for (var mapValue in map.values) {
if (mapValue == value) return i;
i++;
}
return -1;
}
You can search using .where(...) if you want to find all that match or firstWhere if you assume there can only be one or you only want the first
var found = xmenObj.keys.firstWhere(
(k) => xmenObj[k] == '4xmen', orElse: () => null);
print(xmenObj[found]);

How can I use a HashMap of List of String in Vala?

I am trying to use a HashMap of Lists of strings in Vala, but it seems the object lifecycle is biting me. Here is my current code:
public class MyClass : CodeVisitor {
GLib.HashTable<string, GLib.List<string>> generic_classes = new GLib.HashTable<string, GLib.List<string>> (str_hash, str_equal);
public override void visit_data_type(DataType d) {
string c = ...
string s = ...
if (! this.generic_classes.contains(c)) {
this.generic_classes.insert(c, new GLib.List<string>());
}
unowned GLib.List<string> l = this.generic_classes.lookup(c);
bool is_dup = false;
foreach(unowned string ss in l) {
if (s == ss) {
is_dup = true;
}
}
if ( ! is_dup) {
l.append(s);
}
}
Note that I am adding a string value into the list associated with a string key. If the list doesn't exist, I create it.
Lets say I run the code with the same values of c and s three times. Based some printf debugging, it seems that only one list is created, yet each time it is empty. I'd expect the list of have size 0, then 1, and then 1. Am I doing something wrong when it comes to the Vala memory management/reference counting?
GLib.List is the problem here. Most operations on GLib.List and GLib.SList return a modified pointer, but the value in the hash table isn't modified. It's a bit hard to explain why that is a problem, and why GLib works that way, without diving down into the C. You have a few choices here.
Use one of the containers in libgee which support multiple values with the same key, like Gee.MultiMap. If you're working on something in the Vala compiler (which I'm guessing you are, as you're subclassing CodeVisitor), this isn't an option because the internal copy of gee Vala ships with doesn't include MultiMap.
Replace the GLib.List instances in the hash table. Unfortunately this is likely going to mean copying the whole list every time, and even then getting the memory management right would be a bit tricky, so I would avoid it if I were you.
Use something other than GLib.List. This is the way I would go if I were you.
Edit: I recently added GLib.GenericSet to Vala as an alternative binding for GHashTable, so the best solution now would be to use GLib.HashTable<string, GLib.GenericSet<string>>, assuming you're okay with depending on vala >= 0.26.
If I were you, I would use GLib.HashTable<string, GLib.HashTable<unowned string, string>>:
private static int main (string[] args) {
GLib.HashTable<string, GLib.HashTable<unowned string, string>> generic_classes =
new GLib.HashTable<string, GLib.HashTable<unowned string, string>> (GLib.str_hash, GLib.str_equal);
for (int i = 0 ; i < 3 ; i++) {
string c = "foo";
string s = i.to_string ();
unowned GLib.HashTable<unowned string, string>? inner_set = generic_classes[c];
stdout.printf ("Inserting <%s, %s>, ", c, s);
if (inner_set == null) {
var v = new GLib.HashTable<unowned string, string> (GLib.str_hash, GLib.str_equal);
inner_set = v;
generic_classes.insert ((owned) c, (owned) v);
}
inner_set.insert (s, (owned) s);
stdout.printf ("container now holds:\n");
generic_classes.foreach ((k, v) => {
stdout.printf ("\t%s:\n", k);
v.foreach ((ik, iv) => {
stdout.printf ("\t\t%s\n", iv);
});
});
}
return 0;
}
It may seem hackish to have a hash table with the key and value having the same value, but this is actually a common pattern in C as well, and specifically supported by GLib's hash table implementation.
Moral of the story: don't use GLib.List or GLib.SList unless you really know what you're doing, and even then it's generally best to avoid them. TBH we probably would have marked them as deprecated in Vala long ago if it weren't for the fact that they're very common when working with C APIs.
Vala's new can be a little weird when used as a parameter. I would recommend assigning the new list to a temporary, adding it to the list, then letting it go out of scope.
I would also recommend using libgee. It has better handling of generics than GLib.List and GLib.HashTable.

Using __arglist with a varying set of named parameters

in my application I have 2 layers. The first layer is a C legacy exposing cdecl functions that use the "..." syntax for a varying parameter list. The only way I found to call these functions from my .Net layer (the second one) is using the DllImport technics. For example the C function below:
int myFunc(char* name, ...);
looks like that in C#:
[DllImport("MyDll.dll"),
CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.Cdecl]
int myFunc(string name, __arglist);
My problem is that sometimes I want to call this function with 2 extra parameters but if one of them is NULL it won't be included in the argument list (my legacy code fails on NULL values). For example I want this call:
int foo(string name, string a, string b)
{
myFunc(name, __arglist(a, b));
}
{
foo("john", "arg1", null);
}
to be interpreted by C as
myFunc("john", "arg1");
Unfortunately doing something like that:
int foo(string name, string a, string b)
{
List<string> args = new List<string>();
if(a != null) args.Add(a);
if(b != null) args.Add(b);
myFunc(name, __arglist(args));
}
{
foo("john", "arg1", null);
}
is interpreted by C like that:
myFunc(name, args);
and not:
myFunc(name, args[0]);
Does anybody have any idea?
How does the C function know which one is the last parameter? It cannot know a priori how many parameters there are. It needs additional information. One common way for functions get the information they need is by parsing the included string parameter to count format specifiers, as in printf. In that case, if the format string only indicates that there is one extra parameter, then the function doesn't know the difference between a call that really had just one extra parameter and a call that had two or a call that had 20. The function should have the self-discipline to only read one parameter, since that's all the format string said there was. Reading more would lead to undefined behavior.
If what I've described is not the way your function works, then there's not much you can do on the calling end to solve it. But if it is how your function works, then there's nothing to do on the calling end, because there's no problem.
Another option, since you indicate that your "legacy code fails on null values," is to fix your legacy code so it doesn't fail anymore.
A third option is to simply write all four possibilities:
if (a != null) {
if (b != null)
return myFunc(name, a, b);
else
return myFunc(name, a);
} else {
if (b != null)
return myFunc(names, b);
else
return myFunc(names);
}
More than two optional parameters, though, and the code starts getting unwieldy.
Try converting your System.List ToArray() before wrapping it in __arglist
myFunc(name, __arglist(args.ToArray()));

Resources