Practicando Python: LINQ a Python

Esto es un ejercicio personal, tanto para repasar algunas funcionalidades de Linq que no uso diariamente como para aprender algo de Python. El código no hace exactamente lo mismo (puede que no imprima o que no muestre exacamente el mismo mensaje) , aunque la estructura de datos resultante si es la misma. Esta ‘traduccion’ no implica que todo lo que en C# se hace con LINQ es deba hacer del mismo modo en Python. Ni siquiera que sea recomendable. En ciertos casos  otros mecanismos para lograr los mismos resultados pueden ser más recomendables o acercarse más al estililo Python de hacer las cosas. Ni siquiera las soluciones aportadas pueden considerarse correctas de modo general. Los ejemplos fueron probados con Python version 2.7.4
Los ejemplos de Linq estan sacados de 101 LINQ Samples. En breve publicaré mas ejemplos.

Where – Simple 2
This sample uses where to find all products that are out of stock.
C#:

List<Product> products = GetProductList(); 
var soldOutProducts = 
    from p in products 
    where p.UnitsInStock == 0 
    select p;

Python:

class Product:
def __init__ (self, productName, stock):
    self.Name=productName
    self.UnitsInStocks=stock
products= ( Product('Chai',5), Product('Chang',6), Product('Syrup',0) )
print list(product.Name for product in products if product.UnitsInStocks > 0)

Select – Transformation
This sample uses select to produce a sequence of strings representing the text version of a sequence of ints.
C#:

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 
string[] strings = { "zero", "one", "two", "three",
    "four", "five", "six", "seven", "eight", "nine" }; 
var textNums = 
    from n in numbers 
    select strings[n];

Python:

numbers = ( 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 );
strings = ( "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" )
print list(strings[n] for n in numbers)


SelectMany – Compound from 1
This sample uses a compound from clause to make a query that returns all pairs of numbers from both arrays such that the number from numbersA is less than the number from numbersB.
C#:

int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };
var pairs =
     from a in numbersA
     from b in numbersB
     where a < b
     select new { a, b };

Python:

numbersA = [ 0, 2, 4, 5, 6, 8, 9 ]
numbersB = [ 1, 3, 5, 7, 8 ]
print list ("{0} is less than {1}".format(a,b) for a in numbersA for b in numbersB if a<b)

SelectMany – Compound from 3
This sample uses a compound from clause to select all orders where the order was made in 1998 or later.
C#:

List<Customer> customers = GetCustomerList(); 
var orders = 
    from c in customers 
    from o in c.Orders 
    where o.OrderDate >= new DateTime(1998, 1, 1) 
    select new { c.CustomerID, o.OrderID, o.OrderDate };

Python:

from datetime import datetime
class Customer:
  def __init__ (self, name, orders):
    self.Name = name
    self.Orders = orders
  pass
class Order:
  def __init__ (self, date):
    self.OrderDate = date
  pass
print [ (c.Name,o.OrderDate) for c in customers for o in c.Orders if o.OrderDate < datetime(1998,1,1)]

SelectMany – Indexed
This sample uses an indexed SelectMany clause to select all orders, while referring to customers by the order in which they are returned from the query.
C#:

List<Customer> customers = GetCustomerList(); 
var customerOrders = 
    customers.SelectMany( 
        (cust, custIndex) => 
        cust.Orders.Select(o => "Customer #" + (custIndex + 1) + 
                                " has an order with OrderID " + o.OrderID));  

Python:
(nótese que linq requiere de SelectMany porque de otro modo los datos resultantes tienen dos niveles de anidamiento)

print list((index,o.Id) for index, c in enumerate (customers) for o in c.Orders)

skip – Nested
This sample uses Take to get all but the first 2 orders from customers in Washington.
C#:

List<Customer> customers = GetCustomerList();
var waOrders =
    from c in customers
    from o in c.Orders
    where c.Region == "WA"
    select new { c.CustomerID, o.OrderID, o.OrderDate };
    var allButFirst2Orders = waOrders.Skip(2);

Python:

waOrders= [o.OrderDate for c in customers if c.Region=="WA" for o in c.Orders]
allButFirst20Orders= waOrders[2:]
print allButFirst20Orders

TakeWhile – Simple
This sample uses TakeWhile to return elements starting from the beginning of the array until a number is hit that is not less than 6.
C#:

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6); 

Python:
Hay varias maneras, pero con itertools me parece de lo más legible

numbers = [ 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 ]
print list(itertools.takewhile(lambda x: x<5, [1,4,6,4,1]) )


SkipWhile – Simple
This sample uses SkipWhile to get the elements of the array starting from the first element divisible by 3.
C#:

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var allButFirst3Numbers = numbers.SkipWhile(n => n % 3 != 0);

Python:

print list(itertools.dropwhile(lambda x: x % 3 !=0, numbers))

OrderBy – Comparer
This sample uses an OrderBy clause with a custom comparer to do a case-insensitive sort of the words in an array.
C#:

public void Linq31() 
{ 
    string[] words = { "aPPLE", "AbAcUs", "bRaNcH", "BlUeBeRrY", "ClOvEr", "cHeRry" }; 
    var sortedWords = words.OrderBy(a => a, new CaseInsensitiveComparer()); 
    ObjectDumper.Write(sortedWords); 
} 
public class CaseInsensitiveComparer : IComparer<string> 
{ 
    public int Compare(string x, string y) 
    { 
        return string.Compare(x, y, StringComparison.OrdinalIgnoreCase); 
    } 
} 

Python:

words = ["aPPLE", "AbAcUs", "bRaNcH", "BlUeBeRrY", "ClOvEr", "cHeRry" ]
print sorted(words, lambda x,y: cmp(x.lower(),y.lower()))

GroupBy – Simple 1
This sample uses group by to partition a list of numbers by their remainder when divided by 5.
C#:

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 
var numberGroups = 
    from n in numbers 
    group n by n % 5 into g 
    select new { Remainder = g.Key, Numbers = g }; 

Python:
Atención al sorted previo a la agrupación; es necesario porque el groupby de itertools realmente hace ‘rupturas de control’

numbers = [ 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 ]
numbers = sorted(numbers, lambda x, y : cmp( x % 5, y % 5))
for key, group in itertools.groupby(numbers, lambda x: x % 5):
    print "Numbers wit a remainder " + str(key)
    for number in group:
        print number

Distinct
This sample uses Distinct to remove duplicate elements in a sequence of factors of 300.
C#:

int[] factorsOf300 = { 2, 2, 3, 5, 5 };
var uniqueFactors = factorsOf300.Distinct();

Python:
Sobe cuestiones de performance ver http://www.peterbe.com/plog/uniqifiers-benchmark

factorsOf300 = [ 2, 2, 3, 5, 5 ]
print list(set(factorsOf300 ))

Union
This sample uses Union to create one sequence that contains the unique values from both arrays.
C#:

int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };
var uniqueNumbers = numbersA.Union(numbersB);

Python:

## usando set() para eliminar duplicados, cosa que Union() hace automaticamente
numbersA = [ 0, 2, 4, 5, 6, 8, 9 ];
numbersB = [ 1, 3, 5, 7, 8 ];
print list(set(numbersA + numbersB))

Intersect
This sample uses Intersect to create one sequence that contains the common values shared by both arrays.
C#:

int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };
var commonNumbers = numbersA.Intersect(numbersB);

Python:

numbersA = [ 0, 2, 4, 5, 6, 8, 9 ]
numbersB = [ 1, 3, 5, 7, 8 ]
print [ i for i in numbersA if i in numbersB]
print list(set.intersection(set(numbersA), set(numbersB)))
print set(numbersA) & set(numbersB)

Except
This sample uses Except to create a sequence that contains the values from numbersAthat are not also in numbersB.
C#:

int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };
IEnumerable aOnlyNumbers = numbersA.Except(numbersB);

Python:

numbersA = [ 0, 2, 4, 5, 6, 8, 9 ];
numbersB = [ 1, 3, 5, 7, 8 ];
a = Counter(numbersA )
b = Counter(numbersB)
print list((a-b).elements())
Anuncios
Tagged with: , , ,
Publicado en Programacion

Deixa a túa opinión

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: