domingo, 27 de marzo de 2016

Pregunta C# (20 de 20): ¿Cómo Retornar Múltiples Valores desde una Función?

Índice

1. Introducción
2. Palabras Clave
3. Contexto
3.1 Firma de una función en C#
4. Retorno de Múltiples Valores desde una Función
5. Recursos
6. Conclusiones
7. Literatura & Enlaces

1. Introducción

Última pregunta de la serie Twenty C# Questions Answered del curso disponible en Microsoft Virtual Academy. En esta pregunta se responde a la pregunta común de cómo retornar múltiples valores desde una función escrita en C#. Para responderla se recurre a la creación de una clase como estructura de contención de los valores máximo y mínimo, y la escritura de una función que realiza el cómputo del mínimo y máximo.

2. Palabras Clave

  • C#
  • Clase
  • Estructura
  • Función
  • Microsoft Virtual Academy
  • MVA

3. Contexto

3.1 Firma de una función en C#

En el lenguaje de programación C# la declaración de una función sigue la siguiente sintaxis (versión simplificada):

{modificador acceso} {tipo retorno} {nombre función}({parámetros})
{
    {instrucción 1}
    {instrucción 2}
    {instrucción n}

    [return {constante o variable de retorno}]
}

Suponiendo que se quiere declarar el método para la suma de dos valores enteros, entonces la función escrita en código fuente queda así:

public int Sumar(int a, int b)
{
return a + b;
}

El tipo de retorno de una función puede ser cualquier tipo de dato por valor o un tipo de dato por referencia -Tipos por Valor vs. Tipos por Referencia en C#-; lo que quiere decir que se puede retornar una instancia de una estructura -Structs en C#- o de una clase -Clases en C#-.

Esto último permite al programador construir un tipo de dato como contenedor de múltiples valores. La instancia de un tipo de dato como el anterior puede resultar de enorme utilidad para retornar varios valores a una ubicación de código que invoca a una determinada función.

4. Retorno de Múltiples Valores desde una Función

En el siguiente código fuente C# se declara la estructura MaximoMinimo para contener los valores máximo y mínimo de una colección de valores numéricos computados desde una función.

La estructura MaximoMinimo se declara en las líneas 31-60 con las siguientes propiedades:
  • Maximo, y 
  • Minimo
Esta estructura servirá como contenedora de los múltiples valores que retorna el método ObtenerMaximoMinimo(int[]). Este método recibe como argumento un arreglo de enteros y realiza las siguientes operaciones:
  • Línea 23: creación de instancia de MaximoMinimo.
  • Línea 24: asignación del máximo del arreglo valores a la propiedad Maximo de MaximoMinimo. Max() ("Enumerable.Max(TSource)", 2016) es un método de extensión definido en el namespace System.Linq.
  • Línea 25: asignación del mínimo del arreglo valores a la propiedad Minimo de MaximoMinimoMin() ("Enumerable.Min(TSource)", 2016) es un método de extensión definido en el namespace System.Linq.
  • Línea 27: retorno de la instancia MaximoMinimo.
[Aclaración: Una clase también constituye una alternativa como contenedor de los valores máximo y mínimo; sin embargo para efectos de simplicidad se optó por una estructura por la baja complejidad de demanda este caso de ejemplo.]

En el método Main, en particular en la línea 17, se muestra el valor máximo y mínimo calculado en el método ObtenerMaximoMinimo().

Compilación:

csc /t:exe MultiplesValoresRetorno.cs

Ejecución assembly

.\MultiplesValoresRetorno.exe

Demostración ejecución assembly (ideone.com): 

Máximo: 61; mínimo: 5

Demostración ejecución assembly (local): 
Ejecución assembly MultiplesValoresRetorno.exe
Figura 1. Ejecución assembly MultiplesValoresRetorno.exe.

5. Recursos

Este es el vídeo en donde el equipo de expertos Gerry O'Brein y Paul Pardi de MVA, responden y explican esta pregunta:

6. Conclusiones

Al finalizar esta pregunta C# se comprendió cómo es posible retornar múltiples valores desde una función: a través de una estructura -como el caso de MaximoMinimo- o por medio de una clase. Para el ejemplo de la sección práctica, se optó por la estructura por su simplicidad.

7. Literatura & Enlaces

Top C# Questions Answered | Microsoft Virtual Academy (2016, marzo 27). Recuperado desde: https://mva.microsoft.com/en-US/training-courses/twenty-c-questions-answered-8298?l=4paONXYy_9604984382
Tipos por Valor vs. Tipos por Referencia (2016, marzo 27). Recuperado desde: http://ortizol.blogspot.com.co/2013/07/tipos-por-valor-vs-tipos-por-referencia.html
Structs en c# (2016, marzo 27). Recuperado desde: http://ortizol.blogspot.com/2014/04/structs-en-c.html
Clases en C# (2016, marzo 27). Recuperado desde: http://ortizol.blogspot.com/2013/10/clases-en-c.html
Enumerable.Max(TSource) Method (IEnumerable(TSource)) (System.Linq) (2016, marzo 27). Recuperado desde: https://msdn.microsoft.com/en-us/library/bb347632(v=vs.110).aspx
Enumerable.Min Method (System.Linq) (2016, marzo 27). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.linq.enumerable.min(v=vs.110).aspx


V

Pregunta C# (19 de 20): ¿Cómo Ordenar un Diccionario por Valor?

Índice

1. Introducción
2. Palabras Clave
3. Contexto
3.1 LINQ
3.2 Dictionary<TKey, TValue>
4. Ordenamiento Diccionario por Valor
5. Recursos
6. Conclusiones
7. Literatura & Enlaces

1. Introducción

Penúltima pregunta C# de la iteración de Twenty C# Questions Answered de Microsoft Virtual Academy. En esta oportunidad se presenta la solución en código fuente C# para ordenar el contenido de un diccionario por valor. Para lograrlo se hace uso de LINQ: una consulta simple de este lenguaje es suficiente, además de simple, para ordenar los elementos por valor de una colección de este tipo.

2. Palabras Clave

  • Colección
  • Diccionario
  • LINQ

3. Contexto

3.1 LINQ

[Nota: En la sección 3.1 de la pregunta C# Pregunta C# (18 de 20): ¿Cómo Eliminar Datos Duplicados de un Arreglo? se explica el uso de este lenguaje de consulta.]

3.2 Dictionary<TKey, TValue;gt;

Con la clase Dictionary<TKey, TValue> ("Dictionary(TKey, TValue) Class" 2016), se representa la estructura de datos basada en llave-valor.

Archivo C# UsoDictionary.cs [Enlace alternativo][Enlace alternativo]:

Compilación:

csc /t:exe UsoDictionary.cs


Ejecución assembly:

.\UsoDictionary.exe


Demostración ejecución assembly (ideone.com): http://ideone.com/QJt2Wl


La extensión `png` está asociada con `SnagIt Editor`.
La extensión `txt` está asociada con `Notepad++`.
La extensión `html` está asociada con `Google Chrome`.
La extensión `docx` está asociada con `Microsoft Word`.


Demostración ejecución assembly (local): 
Ejecución assembly UsoDictionary.exe
Figura 1. Ejecución assembly UsoDictionary.exe.

4. Ordenamiento Diccionario por Valor

En este código de demostración de ordenamiento de los elementos de un diccionario por valor se usa LINQ para crear la consulta de ordenamiento del diccionario.

En la línea 12 se crea un objeto Dictionary con los tipos paramétricos string. Con las líneas 15-19 se agregan los números de 1-5 con sus correspondientes valores como cadenas de caracteres.

Continuando, con la consulta LINQ 

from dicElemento in dicNumeros orderby dicElemento.Value
ascending select dicElemento;

se toma cada elemento del objeto dicNumeros y se ordena por -orderby- por el valor -Value- de cada elemento: dicElemento.Value. Debido a que el tipo de dato para Value es string, el ordenamiento se realiza de forma alfabética en orden ascendente -ascending-.

Con el ciclo foreach de las líneas 26-29 se imprime el diccionario ordenado -dicNumerosOrdenadosPorValor- en la salida estándar.

Compilación:

csc /t:exe OrdenamientoDiccionarioValor.cs

Ejecución assembly

.\OrdenamientoDiccionarioValor.exe

Demostración ejecución assembly (ideone.com): 


[5, Cinco]
[4, Cuatro]
[2, Dos]
[3, Tres]
[1, Uno]

Demostración ejecución assembly (local): 
Ejecución assembly OrdenamientoDiccionarioValor.exe
Figura 2. Ejecución assembly OrdenamientoDiccionarioValor.exe.

5. Recursos

Este es el vídeo en donde el equipo de expertos Gerry O'Brein y Paul Pardi de MVA, responden y explican esta pregunta:

6. Conclusiones

Quedó demostrado que con el lenguaje de consulta integrado LINQ es posible, gracias a su expresividad y poder, ordenar los elementos de un diccionario por valor.

En la última pregunta C# se demuestra cómo retornar múltiples valores desde una función.

7. Literatura & Enlaces

Top C# Questions Answered | Microsoft Virtual Academy (2016, marzo 27). Recuperado desde: https://mva.microsoft.com/en-US/training-courses/twenty-c-questions-answered-8298?l=ZhKJ2WYy_3004984382
Pregunta C# (18 de 20): ¿Cómo Eliminar Datos Duplicados de un Arreglo? (2016, marzo 27). Recuperado desde: http://ortizol.blogspot.com/2016/03/pregunta-csharp-18-de-20-como-eliminar-datos-duplicados-de-un-arreglo.html
Dictionary(TKey, TValue) Class (System.Collections.Generic) (2016, marzo 27). Recuperado desde: https://msdn.microsoft.com/en-us/library/xfhwa508.aspx


V

Pregunta C# (18 de 20): ¿Cómo Eliminar Datos Duplicados de un Arreglo?

Índice

1. Introducción
2. Palabras Clave
3. Contexto
3.1 LINQ
3.2 List<T>
4. Eliminación de Datos Duplicados de un Arreglo
5. Recursos
6. Conclusiones
7. Literatura & Enlaces

1. Introducción

A unas pocas preguntas de terminar esta iteración de artículos C# enfocados a la resolución de preguntas comunes usando el lenguaje de programación C#. En esta ocasión se resuelve la pregunta de cómo eliminar datos duplicados de un arreglo: se presentan dos enfoques distintos: funciones de LINQ y la iteración del arreglo. Al final se muestra cuál de estos dos métodos es más eficiente en cuanto al uso de construcciones y uso de recursos de cómputo.

2. Palabras Clave

  • Arreglo
  • Colección
  • LINQ
  • Lista
  • Terna de Pitágoras

3. Contexto

3.1 LINQ

LINQ ("Language Integrated Query", 2016) -Language Integrated Query- provee una abstracción para la extracción y procesamiento de datos sobre diferentes fuentes de datos: bases de datos relacionales, XML, arreglos, tipos enumerables, objetos en memoria, entre otras más. Cuenta, además, con soporte para ORM.

Como ejemplo básico de uso de LINQ, se puede presentar el cálculo de ternas de Pitágoras:

Enumerable.Range(2, 10)
.Select(c => new {
Longitud = 2 * c,
Altura = c * c - 1,
Hipotenusa = c * c + 1
}).Dump("Ternas de Pitágoras")

Al ejecutar este código se obtiene hasta 10 ternas de Pitágoras ("Terna pitagórica", 2016) empezando con c igual a 2. La ejecución de demostración se realiza en LINQPad y su resultado es:
Ternas de Pitágoras en LINQ
Figura 1. Ternas de Pitágoras en LINQ.
Para saber más acerca de LINQ recomiendo la lectura de estas recetas LINQ (en inglés):
La clase genérica List<T> ("List(T) Class", 2016) representa una lista de objetos indezados. Esta clase contiene definiciones para la búsqueda, ordenamiento y manipulación de objetos. Se halla definida en el namespace System.Collections.Generic.

4. Eliminación de Datos Duplicados de un Arreglo

En esta solución se presentan dos mecanismos programáticos para la eliminación de elementos -datos- duplicados en un arreglo:
  • uso de LINQ, e 
  • iteración de los elementos del arreglo original
En la línea 11 se crea un arreglo de objetos string con diferentes nombres de aplicaciones (algunos duplicados). Con el método EliminarDuplicadosLinq(string[]) se hace uso de LINQ para eliminar duplicados: el método Distinct() ejecuta esta tarea de forma eficiente. Nótese que basta con una línea de código para la eliminación de datos duplicados del arreglo software.


Por otro lado, con el método EliminarDuplicadosIterativo(string[]) se usa un enfoque de eliminación de datos duplicados usando ciclos: en este caso un ciclo foreach. Además es necesario crear una colección de tipo List<string> para insertar los elementos no duplicados. Con el método Contains de esta colección se consulta si el elemento actual del arreglo software ya fue insertado en la lista.

Compilación:

csc /t:exe EliminacionDuplicados.cs

Ejecución assembly

.\EliminacionDuplicados.exe


Demostración ejecución assembly (ideone.com): 



Eliminación duplicados con LINQ:
Evernote
Chrome
TuneIn
Wolfram Alpha
Stack Exchange

Eliminación duplicados con ciclos foreach:
Evernote
Chrome
TuneIn
Wolfram Alpha
Stack Exchange


Demostración ejecución assembly (local): 
Ejecución assembly EliminacionDuplicados.exe
Figura 2. Ejecución assembly EliminacionDuplicados.exe.

5. Recursos

Este es el vídeo en donde el equipo de expertos Gerry O'Brein y Paul Pardi de MVA, responden y explican esta pregunta:

6. Conclusiones

Se usaron dos enfoques distintos para la eliminación de datos duplicados en un arreglo: a través de LINQ y ciclos. El mecanismo de LINQ es mucho más eficiente y expresivo que el basado en ciclos: a nivel de costos computacionales es más eficiente en el uso de tiempo de procesador y espacio de memoria.

En la penúltima pregunta C# se estudia cómo ordenar un diccionario por valor.

7. Literatura & Enlaces

Top C# Questions Answered | Microsoft Virtual Academy (2016, marzo 27). Recuperado desde: https://mva.microsoft.com/en-US/training-courses/twenty-c-questions-answered-8298?l=FcVUiWYy_7504984382
Language Integrated Query (2016, marzo 27). Recuperado desde: https://en.wikipedia.org/wiki/Language_Integrated_Query
LINQ Recipe No. 2-1: Mathematics and Statistics - Compute the Dot Product of Two Vectors (2016, marzo 27). Recuperado desde: http://ortizol.blogspot.com/2016/03/linq-recipe-no-2-1-mathematics-and-statistics-compute-the-dot-product-of-two-vectors.html
LINQ Recipe No. 2-2: Mathematics and Statistics - How to Generate Pythagorean Triples (2016, marzo 27). Recuperado desde: http://ortizol.blogspot.com/2016/03/linq-recipe-no-2-2-mathematics-and-statistics-how-to-generate-pythagorean-triples.html
LINQ Recipe No. 2-3: Mathematics and Statistics - How to Compute a Weighted Sum? (2016, marzo 27). Recuperado desde: http://ortizol.blogspot.com/2016/03/linq-recipe-no-2-3-mathematics-and-statistics-how-to-compute-a-weighted-sum.html
List(T) Class (System.Collections.Generic) (2016, marzo 27). Recuperado desde: https://msdn.microsoft.com/en-us/library/6sh2ey19.aspx
Terna pitagórica (2016, marzo 27). Recuperado desde: https://es.wikipedia.org/wiki/Terna_pitag%C3%B3rica


V

Pregunta C# (17 de 20): ¿Cómo Redondear un Número Decimal a Dos Posiciones Decimales?

Índice

1. Introducción
2. Palabras Clave
3. Contexto
3.1 Especificadores estándar de formato número
3.1.1 Sobrecarga del método ToString()
3.1.2 Formato con llaves para parámetros
4. Redondeando un Número Decimal a Dos Posiciones
5. Recursos
6. Conclusiones
7. Literatura & Enlaces

1. Introducción

La manipulación de valores numéricos es quizás una de las tareas más comunes que se pueden llevar a cabo en aplicaciones financieras, científicas, matemáticas. En esta oportunidad se enseña al programador del lenguaje de programación C# a redondear un número decimal a dos posiciones decimales. Para lograrlo se usan lo que se conoce como especificadores de formato; que no son más que cadenas que definen el formato de presentación para valores numéricos.

2. Palabras Clave

  • Decimal
  • Especificador de formato
  • Método sobrecargado

3. Contexto

3.1 Especificadores estándar de formato numérico

En el lenguaje de programación C# se cuenta con un conjunto estándar de especificadores de formato para valores numéricos. La sintaxis para dar formato a valores numéricos sigue estas convenciones:

3.1.1 Sobrecarga del método ToString()

El método ToString() cuenta con una versión sobrecargada que recibe como argumento una cadena de caracteres a modo de formato de valores numéricos. Por ejemplo, en las siguientes líneas de código se utilizan distintos formatos numéricos para valores de moneda, decimales, exponentes:

decimal valor = 987.654m;
Console.WriteLine(valor.ToString("C2")); // $987.65

int valor = 12345;
Console.WriteLine(valor.ToString("D")); // 12345
Console.WriteLine(value.ToString("D8")); // 00012345

double valor = 12345.6789;
Console.WriteLine(valor.ToString("E", CultureInfo.InvariantCulture)); // 1.234568E+004

Nótese cómo en este último caso se utiliza otra de las versiones sobrecargadas de ToString() para especificar la presentación del valor de acuerdo a la configuración regional.

3.1.2 Formato con llaves para parámetros

En C# también se cuenta con un modo alternativo para la especificación del formato de valores numéricos. Éste consiste en el uso de llaves junto con un formato anidado:

{[formato]}

Los ejemplos de la sección anterior -3.1.1- quedan escritos así de acuerdo a este formato:

decimal value = 123.456m;
Console.WriteLine("{0:C2}.", value); $123.46

int valor = 12345;
Console.WriteLine("{0:D}", valor); // 12345
Console.WriteLine("{0:D8}", valor);; // 00012345

Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
double valor = 12345.6789;
Console.WriteLine("{0:E}", valor); // 1.234568E+004

[Nota: En el artículo presentado en "Standard Numeric Format Strings" (2016) se presenta la versión explicativa extendida de estos formatos de presentación de valores numéricos.]

4. Redondeando un Número Decimal a Dos Posiciones

Ahora se escribe un ejemplo con las diferentes variantes de formato de un número de decimal con dos posiciones de precisión:

En la línea 12 se declara la variable decimal valor con el valor 951753456.951753456M con 9 decimales de precisión. El valor original de esta variable se imprime en la salida estándar con la instrucción de la línea 13. Las líneas 17-20 llevan a cabo las siguientes operaciones:
  • Línea 17: usa el especificador de formato #.## para indicar que ToString() deberá imprimir el valor decimal con dos decimales.
  • Línea 18: con el formato {0:0.00} (equivalente a #.##) se indica que el valor decimal debe tener la misma precisión: 2 dígitos.
  • Línea 19: con la cadena de formato N2 se formatea el valor decimal con separador de unidades de mil y de decimal con dos decimales de precisión.
  • Línea 20: el especificador de formato {0:C} se formatea el valor decimal como un valor de moneda; también con dos decimales de precisión por defecto.
Compilación:

csc /t:exe FormatoDecimal.cs

Ejecución assembly

.\FormatoDecimal.exe

Demostración ejecución assembly (ideone.com): http://ideone.com/FWgkdR

951753456.951753456

951753456.95
951753456.95
951,753,456.95
$951,753,456.95


Demostración ejecución assembly (local): 
Ejecución assembly FormatoDecimal.exe
Figura 1. Ejecución assembly FormatoDecimal.exe.

5. Recursos

Este es el vídeo en donde el equipo de expertos Gerry O'Brein y Paul Pardi de MVA, responden y explican esta pregunta:

6. Conclusiones

En esta pregunta C# se demostró cómo formatear un valor decimal con dos decimales de precisión. Ahora se sabe que existen dos alternativas para formatear un valor decimal: con las versiones sobrecargadas de ToString() y las llaves de formato -{[formato]}.

En la próxima pregunta C# se responde cómo eliminar los valores duplicados de un arreglo.

7. Literatura & Enlaces

Top C# Questions Answered | Microsoft Virtual Academy (2016, marzo 27). Recuperado desde: https://mva.microsoft.com/en-US/training-courses/twenty-c-questions-answered-8298?l=yIsvPWYy_8204984382
Standard Numeric Format Strings (2016, marzo 27). Recuperado desde: https://msdn.microsoft.com/en-us/library/dwhawy9k(v=vs.110).aspx


V