I'm new to Fantom, and I've only played around with it for a day or so. I'm having a bit of trouble figuring out how to write a certain function.
The idea is to have a function consuming a list of A, and returning a map from B => lists of A, where the B keys are given by calling a supplied function, F, with A as an argument. So it's sort of like "grouping" the elements in a list depending on some property on each object.
Perhaps code samples are clearer... :-)
The equivalent Ruby code could look something like:
def group(list, func)
m = {}
list.each do |e|
k = func.call(e)
m[k] ||= []
m[k] << e
end
m
end
p group([1,2,3,4,5,6,7,8,9], lambda {|a| a % 2 == 0 ? :even : :odd})
Output:
{:odd=>[1, 3, 5, 7, 9], :even=>[2, 4, 6, 8]}
(There are probably prettier ways to do that; I'm new to Ruby too.)
And in Java you could write it as :
import java.util.*;
public class Group {
static interface Unary<T, U> {
public U call(T arg);
}
static <K, V> Map<K, List<V>> group(Collection<V> coll, Unary<V, K> fun) {
Map<K, List<V>> map = new HashMap<K, List<V>>();
for (V v : coll) {
K key = fun.call(v);
List<V> list = map.get(key);
if (list == null) {
list = new ArrayList<V>();
map.put(key, list);
}
list.add(v);
}
return map;
}
public static void main(String[] args) {
System.out.println(group(
Arrays.asList(1,2,3,4,5,6,7,8,9),
new Unary<Integer, String>() {
public String call(Integer arg) {
return arg % 2 == 0 ? "even" : "odd";
}
}));
}
}
Output:
{even=[2, 4, 6, 8], odd=[1, 3, 5, 7, 9]}
How would I write an equivalent general group() function in Fantom?
DanielFathTue 7 Dec 2010
First off Fantom doesn't support generic programming so I'm gonna reduce the domain to Int[] and map of Str:Int[]. Something like this:
However, the complete translation of Ruby code to Fantom could look like this:
Obj:Obj?[] group(Obj?[] list, |Obj?->Obj| func)
{
m := Obj:Obj?[][:] //m := [:]
list.each |e|
{
k := func(e)
m[k] = m[k] ?: [,]
m[k].add(e) //m[k]->add(e)
}
return m
}
Replacing lines with comments would correspond to solution with dynamic invoke
DanielFathTue 7 Dec 2010
I'm a Java programmer, can't you tell :P
ahhatemTue 7 Dec 2010
class Main
{
static Void main()
{
echo(group([1,2,3,4,5,6,7,8,9], |Int e->Str|{ return e % 2==0?"even" : "Odd"}))
}
static Obj:Obj[] group (Obj[] list, |Obj e->Obj| func)
{
Obj:Obj[] map := [:]
list.each |Obj e|{
k := func(e)
map[k] = map[k] ?: [,]
// if (!map.containsKey(k)) map[k] = Obj[,]
map[k].add(e)
}
return map
}
}
perpTue 7 Dec 2010
Great answers, everyone, thanks! I'm starting to like this language. :-)
vkuzkokovTue 7 Dec 2010
Actually m.getOrAdd(k) { Int[,] } is closer than m[k] = m[k] ?: [,] because there's no unnecessary set in the former. The flipside is an extra closure.
BTW, Ivan's example optimizes away second get. Ruby equivalent would be (AFAIK it's valid Ruby) (m[k] ||= []) << e.
perp Tue 7 Dec 2010
I'm new to Fantom, and I've only played around with it for a day or so. I'm having a bit of trouble figuring out how to write a certain function.
The idea is to have a function consuming a list of A, and returning a map from B => lists of A, where the B keys are given by calling a supplied function, F, with A as an argument. So it's sort of like "grouping" the elements in a list depending on some property on each object.
Perhaps code samples are clearer... :-)
The equivalent Ruby code could look something like:
Output:
(There are probably prettier ways to do that; I'm new to Ruby too.)
And in Java you could write it as :
Output:
How would I write an equivalent general group() function in Fantom?
DanielFath Tue 7 Dec 2010
First off Fantom doesn't support generic programming so I'm gonna reduce the domain to
Int[]
and map ofStr:Int[]
. Something like this:Note:
func.call(i)
andfunc(i)
are the same.func(i)
is just a shortcut forcall
method.ivan Tue 7 Dec 2010
Writing in DanielFath's domain, I'd rather write it like this:
prints:
However, the complete translation of Ruby code to Fantom could look like this:
Replacing lines with comments would correspond to solution with dynamic invoke
DanielFath Tue 7 Dec 2010
I'm a Java programmer, can't you tell :P
ahhatem Tue 7 Dec 2010
perp Tue 7 Dec 2010
Great answers, everyone, thanks! I'm starting to like this language. :-)
vkuzkokov Tue 7 Dec 2010
Actually
m.getOrAdd(k) { Int[,] }
is closer thanm[k] = m[k] ?: [,]
because there's no unnecessaryset
in the former. The flipside is an extra closure.BTW, Ivan's example optimizes away second
get
. Ruby equivalent would be (AFAIK it's valid Ruby)(m[k] ||= []) << e
.