5

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
  • So what's your question? Commented Jan 24, 2010 at 20:58

4 Answers 4

3

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);
Sign up to request clarification or add additional context in comments.

10 Comments

Nice =) Is it possible to do this with generics as well, i.e. to use Enumerable<double> (or IEnumerable<double>) instead of Enumerable?
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.
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: Good catch. The outer repeat is necessary though.
@dtb: Sorry, I'm not too familiar with the collection libraries in .NET
|
1

[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.

Comments

1

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)

Comments

1

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]]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.