tags:

views:

255

answers:

4
def divideset(rows, column, value)
split_function = nil

if value.is_a?(Fixnum) || value.is_a?(Float)
  split_function = lambda{|row| row[column] >= value}
else
  split_function = lambda{|row| row[column] == value}
end

set1 = rows.select{|row| split_function.call(row)}
set2 = rows.reject{|row| split_function.call(row)}
[set1, set2]
end

In this code from treepredict, why use lambdas?

It seems that instead of calling split_function.call(row), the author could have predefined two different methods to handle the two conditions of the if/else statement -- one for the case where row[column] >= value and the other for the case where row[column] == value

Is there any additional advantage here from using the lambda?

+2  A: 

You could predefine these 2 function and then use them.

But using lambda in this case is much clear as these are really trival functions and their scope is only limited within divideset. If some other functions would also use the some functionality , it is better to use predefined function to follow the DRY principle.

pierr
+2  A: 

There is no additional technical advantage to using the lambdas in this case.

Consider your suggestion:

def split_function_default(row, column, value)
  row[column] == value
end

def split_function_number(row, column, value)
  row[column] >= value
end

def divideset(rows, column, value)
  set1 = nil
  set2 = nil
  if value.is_a?(Fixnum) || value.is_a?(Float)
    set1 = rows.select{|row| split_function_number(row, column, value)}
    set2 = rows.reject{|row| split_function_number(row, column, value)}
  elif
    set1 = rows.select{|row| split_function_default(row, column, value)}
    set2 = rows.reject{|row| split_function_default(row, column, value)}
  end
  [set1, set2]
end

Which is more clear? Personally, I prefer the lambda version as it's more succinct.

Brannon
Now that you write it out like that, it becomes pretty clear. Thanks.
uzo
They could have used Array#partition as well: `set1,set2 = rows.partition { |row| split_function[row] }`
rampion
A: 

In a sense it's just style, but every little bit helps

Although in one view it's just style, in another it does show the capability of a functional language to get the same amount of work done with less peon labor. If we didn't care about verbosity and clunkiness we could just write everything in Java...

Here are some rather minor "style" variations that come to mind:

def divideset(rows, column, value)
  split_function = value.is_a?(Fixnum) || value.is_a?(Float) ?
      lambda {|row| row[column] >= value} :
      lambda {|row| row[column] == value}

  [ rows.select{|row| split_function.call(row)},
    rows.reject{|row| split_function.call(row)} ]
end


def divideset(rows, column, value)
  split_function =
    if value.is_a?(Fixnum) || value.is_a?(Float) 
      lambda {|row| row[column] >= value} 
    else
      lambda {|row| row[column] == value}
    end

  [ rows.select{|row| split_function.call(row)},
    rows.reject{|row| split_function.call(row)} ]
end

Perhaps I've been playing too much code-golf.

DigitalRoss
BTW, if you want to play code-golf with this function yourself you can test it with the following input: **divideset([[1, 2, 3], [4, 5, 6], [7, 8, 9]], 1, 4)** which should produce **[[[4, 5, 6], [7, 8, 9]], [[1, 2, 3]]]**
DigitalRoss
+1  A: 

Just chiming in, for the record.

split_function = lambda {|row| do_stuff_with(row) }

// don't do this
rows.select{|row| split_function.call(row)}

// do this
rows.select(&split_function)
August Lilleaas