support for reduce in query language?
Posted:
Thu Dec 12, 2013 12:38 am
by kobi7
Hi,
Is there support for something like reduce or aggregate in the
for syntax?
for example
for p in plants reduce ( (p1,p2 ) p1.radius < p2.radius ) get p1
or something similar.
in other words, have a function that takes two items, and returns one.
This can be implemented as
p1 = plants[0]
for p in plants
if p.radius < p1.radius
p1 = p
return p1
maybe return nil if the list is empty?
Re: support for reduce in query language?
Posted:
Thu Dec 12, 2013 4:54 pm
by ObtuseAngle
Here's a simple starting point:
- Code: Select all
class TestReduce
sig SomeReducingFunction(a as int, b as int) as int
def lesser(a as int, b as int) as int
if a < b
return a
else
return b
def reduce(aList as List<of int>, aReducingFunction as SomeReducingFunction, initialValue as int) as int
result = initialValue
for item in aList
result = aReducingFunction(item, result)
return result
def main
i = 5
myList = [3, 4, 5, 6, 7]
reducingFunction as SomeReducingFunction = ref .lesser
print .reduce(myList, reducingFunction, i)
Re: support for reduce in query language?
Posted:
Thu Dec 12, 2013 6:57 pm
by Charles
Thanks ObtuseAngle. Here is a slight evolution which allows the initial value to be unspecified provided the list has at least one element. I also separated out the delegate and utility method similar to what I would do in an actual application:
EDIT: And I changed the type from List<of int> to IList<of int>.
sig ReducingFunction(a as int, b as int) as int
class Utils
shared
def reduce(list as IList<of int>, func as ReducingFunction, initialValue as int? = nil) as int
require initialValue is not nil or list.count > 0
result = initialValue ? list[0]
for item in list, result = func(item, result)
return result
class TestReduce
def lesser(a as int, b as int) as int
if a < b, return a
else, return b
def main
i = 5
myList = [4, 5, 3, 6, 7]
# can use like this:
reducingFunction as ReducingFunction = ref .lesser
print Utils.reduce(myList, reducingFunction, i)
# or simply:
print Utils.reduce(myList, ReducingFunction(ref .lesser), i)
# and without an initial value passed in:
print Utils.reduce(myList, ref .lesser) == 3
Re: support for reduce in query language?
Posted:
Thu Dec 12, 2013 7:43 pm
by Charles
And now a generic version with tests for ints and strings. I made it an extension method so you can slap a ".reduce" on any list you refer to. I also added an example of specifying the reduction function "inline" with the "do" feature.
I really wouldn't have gotten to this tonight if ObtuseAngle hadn't gotten it started. I became obsessed. "That has to be made generic!"
Enjoy!
extend IList<of T>
def reduce(func as Func<of T, T, T>) as T
require .count > 0
result = this[0]
for i in 1 : .count, result = func(result, this[i])
return result
def reduce(func as Func<of T, T, T>, initialValue as T) as T
result = initialValue
for item in this, result = func(result, item)
return result
class TestReduce
shared
def lesser(a as int, b as int) as int
if a < b, return a
else, return b
def greater(a as String, b as String) as String
if a.toLower > b.toLower, return a
else, return b
def main
.testString
.testInt
def testString
names = ['m', 'z', 'a', 'b']
# example: refer to a method for reducing
last = names.reduce(ref .greater)
assert last == 'z'
# example: inline the reduction method
last = names.reduce(do(a as String, b as String))
if a.toLower > b.toLower, return a
else, return b
assert last == 'z'
def testInt
i = 50_000
myList = [4, 5, 3, 6, 7]
# example A
j = myList.reduce(ref .lesser)
assert j == 3
# example B
j = myList.reduce(ref .lesser, i)
assert j == 3
# example C
func as Func<of int, int, int> = ref .lesser
j = myList.reduce(func, i)
assert j == 3
Re: support for reduce in query language?
Posted:
Thu Dec 12, 2013 10:54 pm
by ObtuseAngle
Ooh, I like that list extension - elegant. Thanks for that example!
Inline functions, on the other hand, generally tend to grate on my nerve endings - but that is perhaps a closer solution to kobi7's request.
Re: support for reduce in query language?
Posted:
Sat Dec 14, 2013 10:37 am
by kobi7
oooh!! thank you guys!
that's a really nice present
shall I risk my luck with further requests?