Page 1 of 1

support for reduce in query language?

PostPosted: 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?

PostPosted: 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?

PostPosted: 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?

PostPosted: 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!" :D

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?

PostPosted: 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?

PostPosted: 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? ;-)