desarrolloMobile.NET Noticias

viernes, octubre 30, 2009

GroupBy con LINQ to Objects

El agrupamiento de un conjunto de datos mediante LINQ, ya sea mediante la extensión de IEnumerable o IQueryable, tiene una serie de características las cuales me gustaría comentar aquí.

Para explicar un poco las posibilidades del agrupamiento mediante la extensión GroupBy voy a exponer un ejemplo con LINQ to Objects y para ello, primero, definiremos una clase sencilla que represente la entidad Cliente.

public class Cliente
{
public int IdProvincia { get; set; }
public int Tipo { get; set; }
public string Nombre { get; set; }
public decimal VolumenNegocio { get; set; }

public override string ToString()
{
return string.Format("\t\t-> Cliente: {0} - Provincia:{1} - Tipo: {2} - Vol.:{3}e\n",
Nombre, IdProvincia, Tipo,VolumenNegocio);
}
}

Como se puede observar no es más que una clase con 4 propiedades implícitas y el método ToString() sobrescrito para poder mostrar por la consola la información de un objeto iterado del tipo Cliente.

Vamos a generar una lista de clientes mediante una lista genérica de la siguiente forma:

//inicializamos lista de clientes
var list = new List<Cliente>
{
new Cliente {IdProvincia = 1, Nombre = "Cliente1", Tipo = 10, VolumenNegocio = 100.00m},
new Cliente {IdProvincia = 2, Nombre = "Cliente2", Tipo = 20, VolumenNegocio = 20.00m},
new Cliente {IdProvincia = 3, Nombre = "Cliente3", Tipo = 20, VolumenNegocio = 230.00m},
new Cliente {IdProvincia = 3, Nombre = "Cliente4", Tipo = 20, VolumenNegocio = 500.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente5", Tipo = 30, VolumenNegocio = 10.00m},
new Cliente {IdProvincia = 2, Nombre = "Cliente6", Tipo = 10, VolumenNegocio = 750.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente7", Tipo = 20, VolumenNegocio = 340.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente8", Tipo = 20, VolumenNegocio = 170.00m}
};

La intención es agrupar esta lista de clientes por la provincia, a la cual pertenecen, a través de la propiedad IdProvincia del tipo int. Para ello, en primer lugar, echaremos un vistazo a la extensión GroupBy que incorpora la clase System.Linq.Enumerable. Dicha extensión presenta las siguientes sobrecargas:

public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);

public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TKey, IEnumerable<TSource>, TResult> resultSelector);

public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector);

public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
IEqualityComparer<TKey> comparer);

public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TKey, IEnumerable<TSource>, TResult> resultSelector,
IEqualityComparer<TKey> comparer);

public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
Func<TKey, IEnumerable<TElement>, TResult> resultSelector);

public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
IEqualityComparer<TKey> comparer);

public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
Func<TKey, IEnumerable<TElement>, TResult> resultSelector,
IEqualityComparer<TKey> comparer);



En todas ellas existen un denominador común, el parámetro keySelector del tipo Func<TSource, TElement> que determina el valor de tipo TKey por el cual se agrupara la lista. Por otro lado GroupBy puede retornar un objeto del tipo IEnumerable<TSource> si se especifica el parámetro resultSelector (tipo Func<TSource, TKey>) o bien un objeto del tipo IEnumerable<IGroupingKey<TKey, TElement>> para todos los demás. Vamos centrarnos en éste último por ahora.

Manejando resultados IEnumerable<IGroupingKey<TKey, TElement>>

Si el agrupamiento se realiza sobre una lista de elementos iterativos o “IEnumerables” es obvio que el resultado, otra lista de subelementos agrupados por una clave del tipo TKey, sea otra lista de elementos iterativos de ahí que el tipo resultante sea IEnumerable<T>. La singularidad esta en el tipo genérico en la iteración del valor retornado el cual es del tipo IGroupingKey<TKey,TElement> y vamos a ver el porqué. Lo que LINQ hará ante un GroupBy es realizar un recorrido completo por la lista y seleccionará todos los elementos del tipo TElement de una misma clave (TKey). Por consiguiente el resultado será una lista del agrupamiento de elementos definidos por la interfaz IGroupingKey<TKey,TElement>, en la que almacenará la clave y el conjunto de elemento agrupados por el valor de dicha clave, respetivamente en cada tipo genérico. Veamos un ejemplo.

En nuestra lista de clientes vamos a agrupar los elementos por el identificador de provincia definido por Cliente.IdProvincia. Para ello definiremos una variable del tipo IEnumerable<IGroupingKey<int,Cliente> pues el tipo de datos de agrupamiento es del tipo int (propiedad IdProvincia) y el elemento a agrupar es del tipo Cliente, por tanto:

IEnumerable<IGrouping<int, Cliente>> groupByProv =
from cliente in list group cliente by cliente.IdProvincia;

O lo que es lo mismo:

var groupByProv = list.GroupBy(cliente => cliente.IdProvincia);

Ahora la variable groupByProv posee una lista de todas las clave/agrupaciones realizadas. De hecho podemos comprobarlo de la siguiente forma:

foreach (var cProv in groupByProv)//cProv es del tipo IEnumerable<IGrouping<int, Cliente>>
{
Console.WriteLine(
string.Format("Provincia {0}, {1} clientes", cProv.Key, cProv.Count()));
}

Cuyo resultado por pantalla seria:

image

La variable implícita cProv posee tanto la clave utilizada (IdProvinicia) como la iteración de los clientes agrupados por dicha propiedad, de forma que podría ser recorrida de igual forma.

foreach (var cProv in groupByProv)//cProv es del tipo IEnumerable<IGrouping<int, Cliente>>
{
Console.WriteLine(
string.Format("Provincia {0}, {1} clientes", cProv.Key, cProv.Count()));

foreach(var cliente in cProv)
Console.WriteLine(cliente.ToString());
}

Y es resultado:

image

Sin embargo podríamos rizar aún más el rizo y agrupar, de nuevo, cada una de las agrupaciones por el tipo de cliente. De esta forma tendríamos una primera agrupación según la IdProvincia del cliente y por cada uno, una agrupación por tipo de cliente de la siguiente forma:


   1: foreach (var cProv in groupByProv)//cProv es del tipo IEnumerable<IGrouping<int, Cliente>>


   2: {


   3:     Console.WriteLine(string.Format("Provincia {0} ", cProv.Key));


   4:  


   5:     IEnumerable<IGrouping<int, Cliente>> groupByTipo = cProv.GroupBy(cliente => cliente.Tipo);


   6:  


   7:     foreach (var cTipo in groupByTipo)


   8:     {


   9:         Console.WriteLine(string.Format("\tTipo {0} \n", cTipo.Key));


  10:  


  11:         foreach (var cliente in cTipo)


  12:             Console.WriteLine(cliente.ToString());


  13:     }


  14: }


Lo que hemos hecho en el ejemplo anterior es aprovechar la iteración del primer agrupamiento para volver a generar un extensión GroupBy pero en esta ocasión con la propiedad Cliente.Tipo (int) como TKey. El resultado:

image

Manejando resultados IEnumerable<TSource>

Como comenté anteriormente, GroupBy puede devolver una iteración de tipo IEnumerable<TSource> indicando en la sobrecarga el parámetro resultSelector. Para ver este ejemplo, en base a la lista de cliente generada anteriormente, vamos a mostrar, por ejemplo, para cada una de las provincias (agrupamiento) el número total de clientes, el valor máximo, mínimo y medio de la propiedad Cliente.VolumenNegocio (decimal) de modo que nos ofrecerá información, por cada provincia, de los valores máximo, mínimo y medio del volumen de negocio de los clientes.

Para ello utilizaremos la sobrecarga:


   1: System.Linq.Enumerable.GroupBy<TSource, TKey, TResult>(


   2:    this System.Collections.Generic.IEnumerable<TSource>, 


   3:    System.Func<TSource,TKey>, 


   4:    System.Func<TKey,System.Collections.Generic.IEnumerable<TSource>,TResult>)


La implementación será:


   1: var groupByInfo = list.GroupBy(


   2:     cliente => cliente.IdProvincia, //seguimos con el agrupamiento por provinicia


   3:     (provincia, clientes) => new //retornamos un tipo anónimo


   4:         {


   5:             //con info sobre el agrupamiento


   6:             Key = provincia,


   7:             Count = clientes.Count(),


   8:             Min = clientes.Min(c => c.VolumenNegocio),


   9:             Max = clientes.Max(c => c.VolumenNegocio),


  10:             Avg = clientes.Average(c => c.VolumenNegocio)


  11:         });


El primer lugar, el tipo de la iteración de retorno es del tipo anónimo y es por ello que nos basamos en una variable implícitamente tipada (var). El primer parámetro (línea 2) es del tipo keySelector que vimos anteriormente y como dije es común en todas las sobrecargas pues es el valor clave de agrupamiento. Seguidamente el segundo parámetro (líneas 3-11), del tipo Func<int,IEnumerable<Cliente>,anonymous type> es donde se proyectará el resultado del agrupamiento.

Iteramos y mostramos los resultados.


   1: foreach (var res in groupByInfo)


   2:     Console.WriteLine(


   3:         string.Format("Provinicia:{0}\n\tCount:{1}\n\tMin Volumen:{2}\n\tMax Volumen:{3}\n\tAvg:{4}"


   4:                       , res.Key, res.Count, res.Min, res.Max, res.Avg));


En total 3 iteraciones con sus respectivas “estadísticas”:

image

El código completo:


namespace LINQGroupingBy
{
using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
static void Main(string[] args)
{
//Ejemplo para LINQ to Objects

//inicializamos lista de clientes
var list = new List<Cliente>
{
new Cliente {IdProvincia = 1, Nombre = "Cliente1", Tipo = 10, VolumenNegocio = 100.00m},
new Cliente {IdProvincia = 2, Nombre = "Cliente2", Tipo = 20, VolumenNegocio = 20.00m},
new Cliente {IdProvincia = 3, Nombre = "Cliente3", Tipo = 20, VolumenNegocio = 230.00m},
new Cliente {IdProvincia = 3, Nombre = "Cliente4", Tipo = 20, VolumenNegocio = 500.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente5", Tipo = 30, VolumenNegocio = 10.00m},
new Cliente {IdProvincia = 2, Nombre = "Cliente6", Tipo = 10, VolumenNegocio = 750.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente7", Tipo = 20, VolumenNegocio = 340.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente8", Tipo = 20, VolumenNegocio = 170.00m}
};


//obtenemos todos los clientes agrupados por provincias
var groupByProv = list.GroupBy(cliente => cliente.IdProvincia);

//tambien se puede expresar como:
//
//IEnumerable<IGrouping<int, Cliente>> groupByProv =
// from cliente in list group cliente by cliente.IdProvincia;

foreach (var cProv in groupByProv)//cProv es del tipo IEnumerable<IGrouping<int, Cliente>>
{
Console.WriteLine(
string.Format("Provincia {0}, {1} clientes", cProv.Key, cProv.Count()));

foreach(var cliente in cProv)
Console.WriteLine(cliente.ToString());
}

Console.ReadKey();

foreach (var cProv in groupByProv)//cProv es del tipo IEnumerable<IGrouping<int, Cliente>>
{
Console.WriteLine(string.Format("Provincia {0} ", cProv.Key));

IEnumerable<IGrouping<int, Cliente>> groupByTipo = cProv.GroupBy(cliente => cliente.Tipo);

foreach (var cTipo in groupByTipo)
{
Console.WriteLine(string.Format("\tTipo {0} \n", cTipo.Key));

foreach (var cliente in cTipo)
Console.WriteLine(cliente.ToString());
}
}

Console.ReadKey();
Console.Clear();

//volvemos a agrupar
var groupByInfo = list.GroupBy(
cliente => cliente.IdProvincia, //seguimos con el agrupamiento por provinicia
(provincia, clientes) => new //retornamos un tipo anónimo
{
//con info sobre el agrupamiento
Key = provincia,
Count = clientes.Count(),
Min = clientes.Min(c => c.VolumenNegocio),
Max = clientes.Max(c => c.VolumenNegocio),
Avg = clientes.Average(c => c.VolumenNegocio)
});

//mostramos los resultados
foreach (var res in groupByInfo)
Console.WriteLine(
string.Format("Provinicia:{0}\n\tCount:{1}\n\tMin Volumen:{2}\n\tMax Volumen:{3}\n\tAvg:{4}"
, res.Key, res.Count, res.Min, res.Max, res.Avg));

Console.ReadKey();

}

public class Cliente
{
public int IdProvincia { get; set; }
public int Tipo { get; set; }
public string Nombre { get; set; }
public decimal VolumenNegocio { get; set; }

public override string ToString()
{
return string.Format("\t\t-> Cliente: {0} - Provincia:{1} - Tipo: {2} - Vol.:{3}e\n",
Nombre, IdProvincia, Tipo, VolumenNegocio);
}
}
}
}

domingo, octubre 25, 2009

Un nuevo Bluetooth sólo consumirá una pila de reloj en todo un año

Un nuevo Bluetooth sólo consumirá una pila de reloj en todo un año

Posted using ShareThis

miércoles, octubre 14, 2009

Mas detalles sobre Marketplace Fase 2


En la segunda fase planificada para Noviembre/Diciembre de este mismo año, Marketplace lanzará un entorno para PC. De esta forma podremos se internacionalizará la compra de aplicaciones entre clientes/desarrolladores de diferentes países mediante una nueva caraterística denominada "geo selector". Además estaran disponibles centenares de aplicaciones de pago y gratuitas e incluirá soporte para dispositivos con Windows Mobile 6 / 6.1.


Fuente: modaco.com

sábado, octubre 10, 2009

Listado de recursos de desarrollo para Windows Mobile 6.5

 

A continuación detallo un conjunto de recursos para Windows Mobile 6.X/6.5:

Titulo

Tipo 

Descripción  

Programming for Windows Mobile 6.5

Artículo

Presenta todos los recursos Online para Windows Mobile 6.5

Developing Web Applications for Internet Explorer Mobile 6 on Windows Mobile 6.5

Artículo

 

Como sacar el máximo provecho a las nuevas características del navegador Internet Explorer Mobile de Windows Mobile 6.5.

Developing Widgets for Windows Mobile 6.5

Artículo

Desarrollar Widgets para Windows Mobile 6.5.

Creating Location-Aware Applications for Windows Mobile Devices

Artículo

Desarrollo de aplicaciones basadas en los Servicios Basados en Localización para Windows Mobile 6.x.

Creating a Compelling UI for Windows Mobile and the Microsoft .NET Compact Framework

Artículo

Aprende a utilizar las API’s de la plataforma Windows Mobile® para aumentar la experiencia de usuario.

 

 

Selecting a Windows Mobile API - .NET Compact Framework and Win32

Artículo

 

 

Este artículo habla acerca de Microsoft® Win32® API y las APIs de Microsoft .NET Compact Framework (NETCF) para Windows Mobile® 6 y posterior.

Getting Started with Building Windows Mobile Solutions with Visual Studio and Windows Mobile 6 SDK

Artículo

Como empezar en el desarrollo de aplicaciones para Windows Mobile® utilizando las mismas herramientas que entornos Desktop con Microsoft® Visual Studio® 2008, y específicamente para Microsoft .NET Compact Framework 3.5. También describe como utilizar las herramientas contenidas en el Windows Mobile SDK.

Optimizing Query and DML Performance with SQL Server Compact Edition 3.5 and SqlCeResultSet

Artículo

 

 

Comparación en la inserción y manipulación de filas utilizando Microsoft® SQL Server® Compact Edition 3.5 SP1, con un especial enfoque para el usuario acerca de cómo utilizar los objetos SqlCeResultSet.

Programming Microsoft Synchronization Services for ADO.NET (Devices)

Artículo

Una de las características más importantes de Microsoft® SQL Server® Compact Edition 3.5 SP1 es el soporte a Microsoft Synchronization Services for ADO.NET. Esta tecnología de sincronización permite la sincronización de diferentes orígenes de datos para entornos dos, N capas y arquitecturas orientadas a Servicios.

Porting the Amplitude Application from the iPhone to a Windows Mobile Device – a Case Study

Artículo

Case de estudio documentado de portación de aplicación iPhone a dispositivo Windows Mobile 6.5.

 

 

 

Application Verifier

Blog post

Detalles acerca de los pasos necesarios para la certificación de una aplicación al nuevo Marketplace.

GAPI Deprecation

Blog post

El Games API (GAPI) está obsoleto y este post habla de alternativas.

patterns & practices: Mobile Application Blocks - Community Release (was solution factory)

Codigo

Permite a los desarrolladores desarrollar aplicaciones mobile basadsa en VS2008, .NET CF 3.5 y WM6.1. Basado en el block de Mobile Client Software Factory v1, July 2006 e incluye mejoras realizadas por Microsoft Dynamics Mobile PU.

Using Gestures in Windows Mobile 6.5

Documentación

Documentación para la nueva API de Windows Mobile para el reconocimiento de trazas, Gesture API de Windows Mobile 6.5.

Windows Mobile 6 Professional and Standard Software Development Kits Refresh

Descarga

 

 

 

Requisito para Windows Mobile 6.5 Developer Toolkit (DTK)

Windows Mobile 6.5 Developer Tool Kit

Descarga

Windows Mobile 6.5 Developer Tool Kit (documentación, emuladores,…).

6.5 Developer Resource Kit: (External Order Page)

DVD

 
 

FAQ

FAQ de Marketplace

‘How Do I’ videos

Videos

 

Ramp Up, Windows Mobile 6

Webcasts & Hands on labs

Programa RampUp para desarrollo con Windows Mobile 6.x

Windows Mobile Webcasts

Webcasts

Dos webcast específicos para el nuevo API de Gesture.

Fluid - Windows Mobile 6.x Touch Controls

Codigo

Libreria para .NET 2.0 para Windows Mobile 6.0/6.1 con controles Touch.

Windows Mobile Line of Business Solution Accelerator 2008

Descarga

 

Windows Mobile Line of Business Solution Accelerator es un ejemplo de aplicación Windows Mobile que muestra el uso de diferentes tecnologias (WCF, Sync Services, multi idioma, etc.) en una misma aplicación.