tags:

views:

174

answers:

4

My ultimate aim is to convert the below code in python to C#, but I'd like to do it my self by learning the python syntax. I understand that the code is recursive.

The code produces polynomials of degree n with k variables. More specifically the list of exponents for each variable.

def multichoose(n,k):
    if k < 0 or n < 0: return "Error"
    if not k: return [[0]*n]
    if not n: return []
    if n == 1: return [[k]]
    return [[0]+val for val in multichoose(n-1,k)] + \
        [[val[0]+1]+val[1:] for val in multichoose(n,k-1)]

Here is the conversion I have so far:

public double[] MultiChoose(int n, int k)
{
    if (k < 0 || n < 0)
    {
         throw new Exception();
    }

   if (k == 0)
   {
       return [[0]*n]; // I have no idea what the [[0]*n] syntax means
   }

   if (n == 0)
   {
       return new double[0]; // I think this is just an empty array
   }

   if (n == 1)
   {
       return new double[1] {k}; // I think this is just an empty array
   }

   //Part I don't understand
   return [[0]+val for val in MultiChoose(n-1,k)] + \
        [[val[0]+1]+val[1:] for val in MultiChoose(n,k-1)]
} 

My question is: How do I convert the python code?

+1  A: 

[0] * n returns a list with n 0s. [] is an empty list. [[k]] is a list that contains a list that contains k.

The last part uses list comprehensions. The basic forms of a list comprehension are:

[<new value> for <name> in <sequence>]
[<new value> for <name> in <sequence> if <condition>]

It creates a new list containing the new values each time the optional condition is true.

Ignacio Vazquez-Abrams
+3  A: 

I would use LINQ in C# to translate the code:

  • [] is the empty list.

    Enumerable.Empty<T>()
    
  • [x] is the list containing a single item, x.

    Enumerable.Repeat(x, 1)
    
  • [[0]*n] is the list containing the list containing n copies of 0.

    Enumerable.Repeat(Enumerable.Repeat(0, n), 1)
    
  • [X for Y in Z] is a list comprehension.

    from Y in Z select X
       - or -
    Z.Select(Y => X);
    
  • X + Y (where X and Y are lists) is list concatenation.

    Enumerable.Concat(X, Y)
    

The signature of MultiChoose would be:

 public IEnumerable<IEnumerable<double>> MultiChoose(int n, int k);
dtb
Nice =) Is it possible to do this with generics as well, i.e. to use `Enumerable<double>` (or `IEnumerable<double>`) instead of `Enumerable`?
Tomas Lycken
Enumerable is a static class. It has generic methods that produce IEnumerable<T>'s (I omitted the generic type parameters where they can be inferred), so yes.
dtb
I think you got the [[0]*n] wrong, it should Enumerable.Repeat(Enumerable.Repeat(0, n), 1), also the outer Repeat might not be necessary at all.
Torsten Marek
@Torsten Marek: Good catch. The outer repeat *is* necessary though.
dtb
@dtb: Sorry, I'm not too familiar with the collection libraries in .NET
Torsten Marek
@Torsten Marek: Repeat is the same as *, just more verbose. `[0]*5` = `[0,0,0,0,0]` = Enumerable.Repeat(0, 5). `[0]*1` = `[0]` = Enumerable.Repeat(0, 1). So `[[0]*5]*1` = `[[0,0,0,0,0]]` = Enumerable.Repeat(Enumerable.Repeat(0, 5), 1).
dtb
@dtb: Yes, but isn't there a more direct way of creating an enumerable with just a single item rather than using repeat?
Torsten Marek
@Torsten Marek: You could use an array (which is enumerable), e.g., `new IEnumerable<double>[] { Enumerable.Repeat(0.0, 5) }`. But I think that looks more messy than using Repeat(...,1)
dtb
I can't seem to wrap my head around `[[0]+val for val in MultiChoose(n-1,k)]`It seems MultiChoose returns a list of lists so how come it's not `[[0]]+val` instead of `[0]+val`?
Jonas Elfström
@Jonas Elfström: In `from val in MultiChoose(n-1,k) select [0]+val` (where MultiChoose returns a IEnumerable<IEnumerable<double>>) the variable `val` is a IEnumerable<double>, not a IEnumerable<IEnumerable<double>>.
dtb
But of course, thanks!
Jonas Elfström
+1  A: 

Some comments:

Pythons return "Error" is not throwing an exception. It returns the string value "Error".

Pythons if not k: is not equivalent to if (k == 0) there are more things that are "not", like empty lists, the None value, etc (that may not make a difference in this case).

Pythons foo = [for x in bar] is a list comprehension. It's equivalent to:

foo = []
for x in bar:
   foo.append(x)
Lennart Regebro
+1  A: 

I found this one intriguing and after some help with understanding the Python code I took a stab at it. C# 3.0 and .NET Framework 3.5 needed.

public static IEnumerable<IEnumerable<int>> MultiChoose(int n, int k)
{
    if (k < 0 || n < 0) throw new Exception();
    if (k == 0) return Enumerable.Repeat(Enumerable.Repeat(0, n), 1);
    if (n == 0) return Enumerable.Repeat(Enumerable.Empty<int>(), 0);
    if (n == 1) return Enumerable.Repeat(Enumerable.Repeat(k, 1), 1);

    return (from val in MultiChoose(n - 1, k) select new [] { 0 }.Concat(val))
        .Concat(from val in MultiChoose(n, k - 1) select new [] { val.First() + 1 }.Concat(val.Skip(1)));
}

Here's a version in Ruby

def multichoose(n,k)
  if k<0 || n<0: raise "Error" end
  if k==0: return [[0]*n] end
  if n==0: return [] end
  if n==1: return [[k]] end
  multichoose(n-1,k).map{|val| [0]+val} + \
    multichoose(n,k-1).map{|val| [val.first+1]+val[1..-1]}
end

and some output examples:

>> multichoose(2,2)
=> [[0, 2], [1, 1], [2, 0]]
>> multichoose(3,2)
=> [[0, 0, 2], [0, 1, 1], [0, 2, 0], [1, 0, 1], [1, 1, 0], [2, 0, 0]]
>> multichoose(3,3)
=> [[0, 0, 3], [0, 1, 2], [0, 2, 1], [0, 3, 0], [1, 0, 2], [1, 1, 1], [1, 2, 0], [2, 0, 1], [2, 1, 0], [3, 0, 0]]
Jonas Elfström
+1 - very nice.
dtb