domingo, 22 de septiembre de 2013

29 Clase parcial (partial class)

Hasta ahora hemos visto que una clase se la implementa en dentro de un archivo. El lenguaje C# permite la implementación de una clase en dos o más archivos. Para esto hay que agregarle el modificador partial cuando declaramos la clase.


Este concepto es ámpliamente utilizado por el entorno del .Net en la generación de interfaces visuales.

Como veremos en conceptos futuros es necesario presentar " class" para su entendimiento.

Una clase no es más ni menos que crear una clase completa y luego agrupar métodos y propiedades en dos o más archivos.


Problema 1:

Plantear una clase Rectangulo, definir dos propiedades: Lado1 y Lado2. Definir dos métodos RetornarSuperficie y RetornarPerimetro. Dividir la clase en dos archivos utilizando el concepto de "partial class".

Programa:

Archivo1.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ClaseParcial1
{
    partial class Rectangulo
    {
        private int lado1;
        public int Lado1
        {
            set
            {
                lado1 = value;
            }
            get
            {
                return lado1;
            }
        }
        private int lado2;
        public int Lado2
        {
            set
            {
                lado2 = value;
            }
            get
            {
                return lado2;
            }
        }
    }
}


Archivo2.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ClaseParcial1
{
    partial class Rectangulo
    {
        public int RetornarSuperficie()
        {
            int sup = Lado1 * Lado2;
            return sup;
        }

        public int RetornarPerimetro()
        {
            int per = Lado1 * 2 + Lado2 * 2;
            return per;
        }
    }
}


Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ClaseParcial1
{
    class Program
    {
        static void Main(string[] args)
        {
            Rectangulo rectangulo1 = new Rectangulo();
            rectangulo1.Lado1 = 5;
            rectangulo1.Lado2 = 10;
            Console.WriteLine("La superficie del rectángulo es:" +
                                rectangulo1.RetornarSuperficie());
            Console.WriteLine("El perímetro del rectángulo es:" + 
                                rectangulo1.RetornarPerimetro());
            Console.ReadKey();
        }
    }
}


Para codificar este proyecto procedemos de la siguiente forma:

  1. Seleccionamos desde el menú de opciones Archivo -> Nuevo proyecto...
  2. En el diálogo definimos el nombre del proyecto: ClaseParcial1
  3. Ahora tenemos que agregar los otros archivos. Presionamos el botón derecho del mouse en la ventana del "Explorador de soluciones" sobre el nombre del proyecto ("ClaseParcial1") y seleccionamos la opción Agregar -> Nuevo elemento.
  4. Seleccionamos en el diálogo la plantilla "Clase" y en la parte inferior del diálogo definimos el nombre del archivo, en nuestro caso lo llamamos "archivo1.cs".
  5. En este archivo planteamos la clase "partial class Rectangulo" que define las dos propiedades y atributos.
  6. En forma similar seguimos los crear el archivo2.cs y codificar la clase "partial class Rectangulo" que define los dos métodos.
  7. Finalmente codificamos la clase principal en el archivo Program.cs
    En la main creamos un objeto de la clase Rectangulo e inicializamos las propiedades y llamamos a sus métodos. 

28 Orden de ejecución de los constructores con herencia

Cuando tenemos constructores en las clases y subclases el orden de ejecución de los mismos es :


  Primero se ejecuta el constructor de la clase Padre.
   se ejecuta el constructor de la subclase.


Problema 1:

Plantear tres clases A, B, C que B herede de A y C herede de B. Definir un constructor a cada clase que muestre un mensaje. Luego definir un objeto de la clase C.

Programa:

using System;
using System.Collections.;
using System.Linq;
using System.Text;

namespace Herencia3
{
     A
    {
        public A()
        {
            Console.WriteLine("Constructor de la clase A");
        }
    }

    public class B : A 
    {
        public B()
        {
            Console.WriteLine("Constructor de la clase B");
        }
    }

    public class C : B
    {
        public C()
        {
            Console.WriteLine("Constructor de la clase C");
        }
    }

    class Prueba
    {
        static void Main(string[] args)
        {
            C obj1 = new C();
            Console.ReadKey();
        }
    }
}

Como se puede la ejecución del programa la salida por pantalla es:

Constructor de la clase A
Constructor de la clase B
Constructor de la clase C

Es decir cuando creamos un objeto de la clase C lo primero que se ejecuta es el constructor de la clase de nivel superior (en este caso la clase A), luego el constructor de la clase B y finalmente se ejecuta el constructor de la clase C.



Problema 2:

Plantear tres clases A, B, C que B herede de A y C herede de B. Definir un constructor a cada clase que reciba como parámetro un entero. Luego definir un objeto de la clase C.

Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Herencia4
{
    public class A
    {
        public A(int a)
        {
            Console.WriteLine(a);
        }
    }

    public class B : A
    {
        public B(int b):base(b/2)
        {
            Console.WriteLine(b);
        }
    }

    public class C : B
    {
        public C(int c):base(c/2)
        {
            Console.WriteLine(c);
        }
    }

    class Prueba
    {
        static void Main(string[] args)
        {
            C obj1 = new C(20);
            Console.ReadKey();
        }
    }
}

Como podemos ver la clase el constructor de la clase C debe llamar en forma explícita al constructor de la clase padre mediante la base con el valor a pasar (en este ejemplo le pasamos el parámetro c dividido por dos):

        public C(int c):base(c/2)

En forma similar el constructor de la clase B debe llamar al constructor de la clase A:

        public B(int b):base(b/2)

Si ejecutamos el programa podemos ver que aparece por pantalla los números:

5
10
20


Donde definimos el objeto obj1 pasamos el 20, el constructor de la clase C llama al constructor de la clase B pasando el valor 10, luego el constructor de la clase B llama al constructor de la clase C pasando el valor 5. Como vimos anteriormente primero se ejecuta el constructor de la clase A mostrando el valor 5, seguidamente el constructor de la clase B mostrando el valor 10 y finalmente se ejecuta el constructor de la clase A mostrando el 20.

27 Herencia

Vimos en el concepto anterior que dos clases pueden estar relacionadas por la colaboración. Ahora veremos otro tipo de relaciones entre clases que es la Herencia.

La herencia significa que se pueden crear nuevas clases partiendo de clases existentes, que tendrá todas los , propiedades y los métodos de su 'superclase' o 'clase padre' y además se le podrán añadir otros atributos, propiedades y métodos propios.

clase padre

Clase de la que desciende o deriva una clase. Las clases hijas (descendientes) heredan (incorporan) automáticamente los atributos, propiedades y métodos de la la clase padre.

Subclase

Clase desciendiente de otra. Hereda automáticamente los atributos, propiedades y métodos de su superclase. Es una especialización de otra clase. Admiten la definición de nuevos atributos y métodos para aumentar la especialización de la clase.

Veamos algunos ejemplos teóricos de herencia:

1) Imaginemos la clase Vehículo. Qué clases podrían derivar de ella?
                            Vehiculo

   Colectivo                Moto                    
                             
                                             FordK        Renault 9

Siempre hacia abajo en la jerarquía hay una especialización (las subclases añaden nuevos atributos, propiedades y métodos.

2) Imaginemos la clase . Qué clases podrían derivar de ella?

                                           Software

             DeAplicacion                                        DeBase

ProcesadorTexto       PlanillaDeCalculo                          SistemaOperativo

Word   WordPerfect    Excel     Lotus123                         Linux    Windows       

El primer tipo de relación que habíamos visto clases, es la de colaboración. Recordemos que es cuando una clase contiene un objeto de otra clase como atributo.

Cuando la relación entre dos clases es del tipo "...tiene un..." o "...es parte de...", no debemos implementar herencia. Estamos frente a una relación de colaboración de clases no de herencia.

Si tenemos una ClaseA y otra ClaseB y notamos que entre ellas existe una relacion de tipo "... tiene un...", no debe implementarse herencia sino declarar en la clase ClaseA un atributo de la clase ClaseB.

Por ejemplo: tenemos una clase Auto, una clase Rueda y una clase Volante. Vemos que la relación entre ellas es: Auto "...tiene 4..." Rueda, Volante "...es parte de..." Auto; pero la clase Auto no debe derivar de Rueda ni Volante de Auto porque la relación no es de tipo-subtipo sino de colaboración. Debemos declarar en la clase Auto 4 atributos de tipo Rueda y 1 de tipo Volante.

Luego si vemos que dos clase responden a la pregunta ClaseA "..es un.." ClaseB es posible que haya una relación de herencia.

Por ejemplo:
Auto "es un" Vehiculo
Circulo "es una" Figura
Mouse "es un" DispositivoEntrada
Suma "es una" Operacion


Problema 1:

Ahora plantearemos el primer problema utilizando herencia. Supongamos que necesitamos implementar dos clases que llamaremos Suma y Resta. Cada clase tiene como atributo valor1, valor2 y resultado. Las propiedades a definir son Valor1, Valor2 y Resultado, el método Operar (que en el caso de la clase "Suma" suma los dos y en el caso de la clase "Resta" hace la diferencia entre Valor1 y Valor2.
Si analizamos ambas clases encontramos que muchas propiedades son idénticos. En estos casos es bueno definir una clase padre que agrupe dichas propiedades, atributos y responsabilidades comunes.
La relación de herencia que podemos disponer para este problema es:

                                        Operacion

                        Suma                              Resta

Solamente el método operar es distinto clases Suma y Resta (esto hace que no lo podamos disponer en la clase Operacion), luego las propiedades Valor1, Valor2 son idénticos a las dos clases, esto hace que podamos disponerlos en la clase Operacion. Lo mismo las propiedades Valor1, Valor2 y Resultado se definirán en la clase padre Operacion.


Crear un proyecto y luego crear cuatro clases llamadas: Operacion, Suma, Resta y Prueba


Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Herencia1
{
  
    public class Operacion {
        protected int valor1;
        protected int valor2;
        protected int resultado;

        public int Valor1 
        {
            set 
            {
                valor1=value;
            }
            get
            {
                return valor1;
            }
        }

        public int Valor2 
        {
            set 
            {
                valor2=value;
            }
            get
            {
                return valor2;
            }
        }

        public int Resultado
        {
            protected set 
            {
               resultado=value;
            }
            get
            {
                return resultado;
            }
        }        
    }


    public class Suma: Operacion
    {
        public void Operar() 
        {
            Resultado=Valor1+Valor2;
        }
    }


    public class Resta: Operacion
    {
        public void Operar() 
        {
            Resultado=Valor1-Valor2;
        }
    }

    class Prueba
    {
        static void Main(string[] args)
        {
            Suma suma1 = new Suma();
            suma1.Valor1 = 10;
            suma1.Valor2 = 7;
            suma1.Operar();
            Console.WriteLine("La suma de " + suma1.Valor1 + " y " + 
              suma1.Valor2 + " es " + suma1.Resultado);

            Resta resta1 = new Resta();
            resta1.Valor1 = 8;
            resta1.Valor2 = 4;
            resta1.Operar();
            Console.WriteLine("La diferencia de " + resta1.Valor1 + 
              " y " + resta1.Valor2 + " es " + resta1.Resultado);

            Console.ReadKey();
        }
    }
}

La clase Operación define tres atributos y sus tres propiedades que las acceden:

        protected int valor1;
        protected int valor2;
        protected int resultado;

        public int Valor1 
        {
            set 
            {
                valor1=value;
            }
            get
            {
                return valor1;
            }
        }

        public int Valor2 
        {
            set 
            {
                valor2=value;
            }
            get
            {
                return valor2;
            }
        }

        public int Resultado
        {
            protected set 
            {
               resultado=value;
            }
            get
            {
                return resultado;
            }
        }        

Ya veremos que definimos los atributos con este nuevo modificador de acceso (protected) para que la subclase tenga acceso a dichos atributos. Si los definimos private las subclases no pueden acceder a dichos atributos.

Ahora veamos como es la sintaxis para indicar que una clase hereda de otra:

    public class Suma: Operacion

Disponemos dos puntos y seguidamente el nombre de la clase padre (con esto estamos indicando que todas las propiedades de la clase Operación son también propiedades de la clase Suma.

Luego la característica que añade la clase Suma es el siguiente método:

        public void Operar() 
        {
            Resultado=Valor1+Valor2;
        }

El método Operar puede acceder a las propiedades heredadas (siempre y cuando los mismos se declaren protected, en caso que sean private si bien lo hereda de la clase padre solo los pueden modificar métodos de dicha clase padre)

Ahora podemos decir que la clase Suma tiene tres propiedades y un método.

Luego en otra clase creamos un objeto de la clase Suma:

    class Prueba
    {
        static void Main(string[] args)
        {
            Suma suma1 = new Suma();
            suma1.Valor1 = 10;
            suma1.Valor2 = 7;
            suma1.Operar();
            Console.WriteLine("La suma de " + suma1.Valor1 + " y " + 
              suma1.Valor2 + " es " + suma1.Resultado);

            Resta resta1 = new Resta();
            resta1.Valor1 = 8;
            resta1.Valor2 = 4;
            resta1.Operar();
            Console.WriteLine("La diferencia de " + resta1.Valor1 + 
              " y " + resta1.Valor2 + " es " + resta1.Resultado);

            Console.ReadKey();
        }
    }

Podemos llamar tanto al método propio de la clase Suma "Operar()" como acceder a las propiedades heredadas de la clase Operacion. Quien utilice la clase Suma solo debe conocer que métodos y propiedades públicas tiene (independientemente que pertenezcan a la clase Suma o a una clase superior)
La lógica es similar para declarar la clase Resta.

La clase Operación agrupa en este caso un conjunto de atributos y propiedades comunes a un conjunto de subclases (Suma, Resta). No tiene sentido definir objetos de la clase Operacion.

El planteo de jerarquías de clases es una tarea compleja que requiere un perfecto entendimiento de todas las clases que intervienen en un problema, cuales son sus atributos, propiedades y responsabilidades.


Problema 2:

Confeccionar una clase Persona que tenga como atributos el nombre y la edad (definir las propiedades para poder acceder a dichos atributos). Definir como responsabilidad un método para imprimir.

Plantear una segunda clase Empleado que herede de la clase Persona. Añadir un atributo sueldo ( y su propiedad) y el método para imprimir su sueldo.

Definir un objeto de la clase Persona y llamar a sus métodos y propiedades. También crear un objeto de la clase Empleado y llamar a sus métodos y propiedades.


Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Herencia2
{
    public class Persona
    {
        protected string nombre;
        protected int edad;

        public string Nombre
        {
            set
            {
                nombre = value;
            }
            get
            {
                return nombre;
            }
        }

        public int Edad
        {
            set
            {
                edad = value;
            }
            get
            {
                return edad;
            }
        }

        public void Imprimir()
        {
            Console.WriteLine("Nombre:" + Nombre);
            Console.WriteLine("Edad:" + Edad);
        }
    }

    public class Empleado : Persona
    {
        protected float sueldo;

        public float Sueldo
        {
            set
            {
                sueldo = value;
            }
            get
            {
                return sueldo;
            }
        }

        new public void Imprimir()
        {
            base.Imprimir();
            Console.WriteLine("Sueldo:" + Sueldo);
        }
    }

    class Prueba
    {
        static void Main(string[] args)
        {
            Persona persona1 = new Persona();
            persona1.Nombre = "Juan";
            persona1.Edad = 25;
            Console.WriteLine("Los datos de la persona son:");
            persona1.Imprimir();

            Empleado empleado1 = new Empleado();
            empleado1.Nombre = "Ana";
            empleado1.Edad=42;
            empleado1.Sueldo = 2524;
            Console.WriteLine("Los dats del empleado son:");
            empleado1.Imprimir();

            Console.ReadKey();
        }
    }
}

La clase Persona define los atributos protegidos (protected) nombre y edad. Luego las propiedades públicas Nombre y Edad (que acceden a los atributos para modificarlos o consultar sus valores.


El método imprimir es público para que se lo pueda llamar desde donde definimos un objeto de esta clase.

    public class Persona
    {
        protected string nombre;
        protected int edad;

        public string Nombre
        {
            set
            {
                nombre = value;
            }
            get
            {
                return nombre;
            }
        }

        public int Edad
        {
            set
            {
                edad = value;
            }
            get
            {
                return edad;
            }
        }

        public void Imprimir()
        {
            Console.WriteLine("Nombre:" + Nombre);
            Console.WriteLine("Edad:" + Edad);
        }
    }

La clase Empleado hereda de la clase Persona y agrega un atributo llamado sueldo y la respectiva propiedad Sueldo para acceder al atributo. Como la clase Empleado define otro método Imprimir debemos anteceder la palabla clave new (con esto indicamos que sobreescribimos el método existente en la clase padre.

Para llamar desde el método imprimir de la clase Empleado al método imprimir de la clase Persona es con la sintaxis base.Imprimir()

    public class Empleado : Persona
    {
        protected float sueldo;

        public float Sueldo
        {
            set
            {
                sueldo = value;
            }
            get
            {
                return sueldo;
            }
        }

        new public void Imprimir()
        {
            base.Imprimir();
            Console.WriteLine("Sueldo:" + Sueldo);
        }
    }

Por último en la clase Prueba creamos un objeto de la clase Persona y un objeto de la clase Empleado:


    class Prueba
    {
        static void Main(string[] args)
        {
            Persona persona1 = new Persona();
            persona1.Nombre = "Juan";
            persona1.Edad = 25;
            Console.WriteLine("Los datos de la persona son:");
            persona1.Imprimir();

            Empleado empleado1 = new Empleado();
            empleado1.Nombre = "Ana";
            empleado1.Edad=42;
            empleado1.Sueldo = 2524;
            Console.WriteLine("Los dats del empleado son:");
            empleado1.Imprimir();

            Console.ReadKey();
        }
    }

26 Concepto de propiedad

La mayoría de los lenguajes de programación a objetos acceden a sus atributos a través de métodos. Esto lo vimos en el concepto anterior cuando accedíamos al atributo monto de un cliente:

        public void Depositar(int m)
        {
            monto = monto + m;
        }

        public int RetornarMonto()
        {
            return monto;
        }

Vimos que luego llamamos a dichos métodos con la sintaxis:

    cliente3.Depositar(200);
    cliente3.Extraer(150);

En C# normalmente este tipo de problemas se lo resuelve implementado una propiedad. Veamos el mismo problemas resolviéndolo utilizando propiedades.

Problema 1:

El problema era : Un banco tiene 3 clientes que pueden hacer depósitos y extracciones. También el banco requiere que al final del día calcule la cantidad de dinero depositada.

Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Propiedades1
{
    class Cliente
    {
        private string nombre;
        private int monto;

        public string Nombre
        {
            set
            {
                nombre = value;
            }
            get
            {
                return nombre;
            }
        }

        public int Monto
        {
            set
            {
                monto = value;
            }
            get
            {
                return monto;
            }
        }

        public void Imprimir()
        {
            Console.WriteLine(Nombre + " tiene depositado la suma de " + Monto);
        }
    }

    class Banco
    {
        private Cliente cliente1, cliente2, cliente3;

        public Banco()
        {
            cliente1 = new Cliente();
            cliente1.Nombre = "Juan";
            cliente1.Monto = 0;
            cliente2 = new Cliente();
            cliente2.Nombre = "Ana";
            cliente2.Monto = 0;
            cliente3 = new Cliente();
            cliente3.Nombre = "Pedro";
            cliente3.Monto = 0;
        }

        public void Operar()
        {
            cliente1.Monto = cliente1.Monto + 100;
            cliente2.Monto = cliente2.Monto + 150;
            cliente3.Monto = cliente3.Monto + 200;
        }

        public void DepositosTotales()
        {
            int t = cliente1.Monto + cliente2.Monto + cliente3.Monto;
            Console.WriteLine("El total de dinero en el banco es:" + t);
            cliente1.Imprimir();
            cliente2.Imprimir();
            cliente3.Imprimir();
        }

        static void Main(string[] args)
        {
            Banco banco1 = new Banco();
            banco1.Operar();
            banco1.DepositosTotales();
            Console.ReadKey();
        }
    }
}


Lo más importante es entender que una propiedad es una forma de acceder al contenido de un atributo, tanto para consultar su como modificarlo.

        private string nombre;
        private int monto;

        public string Nombre
        {
            set
            {
                nombre = value;
            }
            get
            {
                return nombre;
            }
        }

        public int Monto
        {
            set
            {
                monto = value;
            }
            get
            {
                return monto;
            }
        }

La propiedad Nombre mediante el modificador set inicializa el atributo nombre con el valor que llega del objeto:
            cliente1.Nombre = "Juan";

Como vemos donde definimos el objeto cliente1 accedemos a la propiedad mediante el punto y le asignamos un valor (en este caso un string porque la propiedad es de tipo string)
Si queremos consultar el atributo nombre lo podemos hacer mediante la propiedad Nombre. Es común definir el nombre que le damos a la propiedad con el mismo nombre que tiene el atributo pero con el primer caracter en mayúsculas:

        //atributo en minúsculas 
        private int monto;
        //nombre de la propiedad con el mismo nombre pero en mayúsculas. 
        public int Monto
        {
            set
            {
                monto = value;
            }
            get
            {
                return monto;
            }
        }

Podemos observar que la sintaxis para acceder a las propiedades donde definimos objetos es intuitiva y sencillas, por ejemplo para saber cuanto dinero hay en el banco la sintaxis con propiedades es:

            int t = cliente1.Monto + cliente2.Monto + cliente3.Monto;
Y como la vimos anteriormente de un método que retorna el monto tenemos la siguiente sintaxis:
int t = cliente1.RetornarMonto () + 
        cliente2.RetornarMonto () + 
        cliente3.RetornarMonto ();

Lo primero que nos viene a la mente es porque no definir los atributos con el modificador public:

        public int monto;

Para luego poder consultarlos y/o modificarlos con la sintaxis:

            int t = cliente1.monto + cliente2.monto + cliente3.monto;

Ahora veamos que cuando consultamos o inicializamos una propiedad en realidad lo que está sucediendo es la ejecución de un método (set o get) donde podemos disponer código donde validar el valor asignado. Por ejemplo si disponemos la restricción que el Monto siempre debe ser positivo para que se almacene, luego debemos codificar la propiedad con la siguiente sintaxis:

        public int Monto
        {
            set
            {
                if (value >= 0)
                {
                    monto = value;
                }
                else
                {
                    Console.WriteLine("No se puede tener un monto negativo.");
                }
            }
            get
            {
                return monto;
            }
        }

Es decir si el valor que le asignamos a la propiedad Monto es negativo luego no se inicializa el atributo monto con dicho valor.

Si ejecutamos este código luego debe mostrar un mensaje indicando que "No se puede tener monto negativo":

 cliente1.Monto = -100;


Problema 2:

Plantear un programa que permita jugar a los dados. Las reglas de juego son: se tiran tres dados si los tres salen con el mismo valor mostrar un mensaje que "gano", sino "perdió".

Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Propiedades2
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace Colaboracion2
    {
        class Dado
        {
            private int valor;

            public int Valor
            {
                get
                {
                    return valor;
                }
                private set
                {
                    valor = value;
                }
            }

            private static Random aleatorio;

            public Dado()
            {
                aleatorio = new Random();
            }

            public void Tirar()
            {
                Valor = aleatorio.Next(1, 7);
            }

            public void Imprimir()
            {
                Console.WriteLine("El valor del dado es:" + Valor);
            }
        }

        class JuegoDeDados
        {
            private Dado dado1, dado2, dado3;

            public JuegoDeDados()
            {
                dado1 = new Dado();
                dado2 = new Dado();
                dado3 = new Dado();
            }

            public void Jugar()
            {
                dado1.Tirar();
                dado1.Imprimir();
                dado2.Tirar();
                dado2.Imprimir();
                dado3.Tirar();
                dado3.Imprimir();
                if (dado1.Valor == dado2.Valor && dado1.Valor == dado3.Valor)
                {
                    Console.WriteLine("Ganó");
                }
                else
                {
                    Console.WriteLine("Perdió");
                }
                Console.ReadKey();
            }

            static void Main(string[] args)
            {
                JuegoDeDados j = new JuegoDeDados();
                j.Jugar();
            }
        }
    }
}

El atributo valor se lo accede por medio de la propiedad Valor:

            private int valor;

            public int Valor
            {
                get
                {
                    return valor;
                }
                private set
                {
                    valor = value;
                }
            }

Luego cuando queremos consultar el valor del dado desde el jugo de dados por medio de la sintaxis siguiente podemos comparar si los tres dados tienen el mismo número:

                if (dado1.Valor == dado2.Valor && dado1.Valor == dado3.Valor)
                {
                    Console.WriteLine("Ganó");
                }
                else
                {
                    Console.WriteLine("Perdió");
                }

Algo importante es poder restringir la ejecución del set o get desde fuera de la clase, por ejemplo en este caso queremos evitar que desde la clase JuegoDeDados se puede cambiar el valor del dado con la siguiente sintaxis:

    dado1.Valor=7;

La línea anterior provocará un error ya que sección del set de la 
propiedad la hemos definido de tipo private (con esto hacemos que solo 
los métodos de la clase puedan ejecuta el set. La sintaxis para acceder a
 la propiedad Valor desde la clase es:

            public void Tirar()
            {
                Valor = aleatorio.Next(1, 7);
            }

Esto es correcto ya que el método Tirar pertenece a la clase Dado y por lo tanto puede asignarle un valor a la propiedad Valor (cuando se asigna un valor a una propiedad se ejecuta el set)


Problemas propuestos


  1. Plantear una clase Club y otra clase Socio.
    La clase Socio debe tener los siguientes atributos privados: nombre y la antigüedad en el club (en años) Definir dos propiedades para poder acceder al nombre y la antigüedad del socio(no permitir cargar un valor negativo en la antigüedad). La clase Club debe tener como atributos 3 objetos de la clase Socio. Definir una responsabilidad para imprimir el nombre del socio con mayor antigüedad en el club. 

25 Colaboración de clases

Normalmente un problema resuelto con la metodología de programación orientada a objetos no interviene una sola clase, sino muchas clases que interactúan y se comunican.
Plantearemos un problema separando las actividades en dos .

Problema 1:

Un banco tiene 3 clientes que pueden hacer depósitos y extracciones. También el banco requiere que al final del día calcule la cantidad de dinero que hay depositada.
Lo primero que hacemos es identificar las clases:
Podemos identificar la clase y la clase Banco.
Luego debemos definir los y los métodos de cada clase:

Cliente  
    atributos
        nombre
        monto
    métodos
        constructor
        Depositar
        Extraer
        RetornarMonto

Banco
    atributos
        3 Cliente (3 objetos de la clase Cliente)
    métodos
        constructor
        Operar
        DepositosTotales

Creamos un proyecto llamado: Colaboracion1 y dentro del proyecto creamos dos clases llamadas: Cliente y Banco.

Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Colaboracion1
{
    class Cliente
    {
        private string nombre;
        private int monto;

        public Cliente(string nom)
        {
            nombre = nom;
            monto = 0;
        }

        public void Depositar(int m)
        {
            monto = monto + m;
        }

        public void Extraer(int m)
        {
            monto = monto - m;
        }

        public int RetornarMonto()
        {
            return monto;
        }

        public void Imprimir()
        {
            Console.WriteLine(nombre+" tiene  la suma de "+monto);
        }
    }

    class Banco
    {
        private Cliente cliente1, cliente2, cliente3;

        public Banco() 
        {
            cliente1=new Cliente("Juan");
            cliente2=new Cliente("Ana");
            cliente3=new Cliente("Pedro"); 
        }

        public void Operar()
        {
            cliente1.Depositar(100);
            cliente2.Depositar(150);
            cliente3.Depositar(200);
            cliente3.Extraer(150);
        }

        public void DepositosTotales()
        {
            int t = cliente1.RetornarMonto () + 
                    cliente2.RetornarMonto () + 
                    cliente3.RetornarMonto ();
            Console.WriteLine ("El total de dinero en el banco es:" + t);
            cliente1.Imprimir();
            cliente2.Imprimir();
            cliente3.Imprimir();
        }

        static void Main(string[] args)
        {
            Banco banco1 = new Banco();
            banco1.Operar();
            banco1.DepositosTotales();
            Console.ReadKey();
        }
    }
}

Analicemos la implementación del problema.


Los atributos de una clase normalmente son privados para que no se tenga acceso directamente desde otra clase, los atributos son modificados por los métodos de la misma clase:

        private string nombre;
        private int monto;

El constructor recibe como parámetro el nombre del cliente y lo almacena en el atributo respectivo e inicializa el atributo monto en cero:

        public Cliente(string nom)
        {
            nombre = nom;
            monto = 0;
        }
Los métodos Depositar y Extraer actualizan el atributo monto con el dinero que llega como parámetro (para simplificar el problema no hemos validado que cuando se extrae dinero el atributo monto quede con un negativo):

        public void Depositar(int m)
        {
            monto = monto + m;
        }

        public void Extraer(int m)
        {
            monto = monto - m;
        }

El método RetornarMonto tiene por objetivo comunicar al Banco la cantidad de dinero que tiene el cliente (recordemos que como el atributo monto es privado de la clase, debemos tener un método que lo retorne):

        public int RetornarMonto()
        {
            return monto;
        }

Por último el método imprimir muestra nombre y el monto de dinero del cliente:

        public void Imprimir()
        {
            Console.WriteLine(nombre+" tiene depositado la suma de "+monto);
        }

Como podemos observar la clase Cliente no tiene función Main. Entonces donde definimos objetos de la clase Cliente?
La respuesta a esta pregunta es que en la clase Banco definimos tres objetos de la clase Cliente.
Veamos ahora la clase Banco que requiere la colaboración de la clase Cliente.
Primero definimos tres atributos de tipo Cliente:

    class Banco
    {
        private Cliente cliente1, cliente2, cliente3;

En le constructor creamos los tres objetos (cada vez que creamos un objeto de la clase Cliente debemos pasar a su constructor el nombre del cliente, recordemos que su monto de depósito se inicializa con cero):

        public Banco() 
        {
            cliente1=new Cliente("Juan");
            cliente2=new Cliente("Ana");
            cliente3=new Cliente("Pedro"); 
        }

El método operar del banco (llamamos a los métodos Depositar y Extraer de los clientes):

        public void Operar()
        {
            cliente1.Depositar(100);
            cliente2.Depositar(150);
            cliente3.Depositar(200);
            cliente3.Extraer(150);
        }

El método DepositosTotales obtiene el monto depositado de cada uno de los tres clientes, procede a mostrarlos y llama al método imprimir de cada cliente para poder mostrar el nombre y depósito:

        public void DepositosTotales()
        {
            int t = cliente1.RetornarMonto () + 
                    cliente2.RetornarMonto () + 
                    cliente3.RetornarMonto ();
            Console.WriteLine ("El total de dinero en el banco es:" + t);
            cliente1.Imprimir();
            cliente2.Imprimir();
            cliente3.Imprimir();
        }

Por último en la Main definimos un objeto de la clase Banco (la clase Banco es la clase principal en nuestro problema):

        static void Main(string[] args)
        {
            Banco banco1 = new Banco();
            banco1.Operar();
            banco1.DepositosTotales();
            Console.ReadKey();
        }

Problema 2:

Plantear un programa que permita jugar a los dados. Las reglas de juego son: se tiran tres dados si los tres salen con el mismo valor mostrar un mensaje que "gano", sino "perdió".
Lo primero que hacemos es identificar las clases:
Podemos identificar la clase Dado y la clase JuegoDeDados.
Luego los atributos y los métodos de cada clase:

Dado  
    atributos
        valor
    métodos
        constructor
        Tirar
        Imprimir
        RetornarValor

JuegoDeDados
    atributos
        3 Dado (3 objetos de la clase Dado)
    métodos
        constructor
        Jugar

Creamos un proyecto llamado: Colaboracion2 y dentro del proyecto creamos dos clases llamadas: Dado y JuegoDeDados.

Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Colaboracion2
{
    class Dado
    {
        private int valor;
        private static Random aleatorio;

        public Dado()
        {
            aleatorio = new Random();
        }

        public void Tirar()
        {
            valor = aleatorio.Next(1, 7);
        }

        public void Imprimir() 
        {
            Console.WriteLine("El valor del dado es:"+valor);
        }

        public int RetornarValor()
        {
            return valor;
        }
    }

    class JuegoDeDados
    {
        private Dado dado1,dado2,dado3;
    
        public JuegoDeDados() 
        {
            dado1=new Dado();
            dado2=new Dado();
            dado3=new Dado();         
        }
    
        public void Jugar() 
        {
            dado1.Tirar();
            dado1.Imprimir();
            dado2.Tirar();
            dado2.Imprimir();
            dado3.Tirar();
            dado3.Imprimir();
            if (dado1.RetornarValor()==dado2.RetornarValor() && 
                dado1.RetornarValor()==dado3.RetornarValor()) 
            {
                Console.WriteLine("Ganó");
            }
            else
            {
                Console.WriteLine("Perdió");
            }
            Console.ReadKey();
        }
    
        static void Main(string[] args)
        {
            JuegoDeDados j = new JuegoDeDados();
            j.Jugar();
        }
    }
}

La clase Dado define el atributo "valor" donde almacenamos un valor aleatorio que representa el número que sale al tirarlo.

Definimos otro atributo de la clase Random. Esta clase nos facilita la generación de un número aleatorio que nos indicará el valor del dato. Como luego se crearán tres objetos de la clase dado y nosotros solo requerimos un objeto de la clase Random luego definimos el atributo de tipo static, con esto todos los objetos de la clase Dado acceden al mismo objeto de la clase Random:


        private int valor;
        private static Random aleatorio;

En el constructor creamos el objeto de la clase Random:

        public Dado()
        {
            aleatorio = new Random();
        }

El método Tirar almacena el valor aleatorio (para generar un valor aleatorio utilizamos el método Next de la clase Random, el mismo genera un valor entero comprendido entre los dos parámetros que le pasamos (nunca genera la cota superior):

        public void Tirar()
        {
            valor = aleatorio.Next(1, 7);
        }

El método Imprimir de la clase Dado muestra por pantalla el valor del dado:

        public void Imprimir() 
        {
            Console.WriteLine("El valor del dado es:"+valor);
        }

Por último el método que retorna el valor del dado (se utiliza en la otra clase para ver si los tres dados generaron el mismo valor):

        public int RetornarValor()
        {
            return valor;
        }

La clase JuegoDeDatos define tres atributos de la clase Dado (con esto decimos que la clase Dado colabora con la clase JuegoDeDados):

    class JuegoDeDados
    {
        private Dado dado1,dado2,dado3;

En el constructor procedemos a crear los tres objetos de la clase Dado:

        public JuegoDeDados() 
        {
            dado1=new Dado();
            dado2=new Dado();
            dado3=new Dado();         
        }

En el método Jugar llamamos al método Tirar de cada dado, pedimos que se imprima el valor generado y finalmente procedemos a verificar si se ganó o no:

        public void Jugar() 
        {
            dado1.Tirar();
            dado1.Imprimir();
            dado2.Tirar();
            dado2.Imprimir();
            dado3.Tirar();
            dado3.Imprimir();
            if (dado1.RetornarValor()==dado2.RetornarValor() && 
                dado1.RetornarValor()==dado3.RetornarValor()) 
            {
                Console.WriteLine("Ganó");
            }
            else
            {
                Console.WriteLine("Perdió");
            }
            Console.ReadKey();
        }

En la Main creamos solo un objeto de la clase principal (en este caso la clase principal es el JuegoDeDados):

        static void Main(string[] args)
        {
            JuegoDeDados j = new JuegoDeDados();
            j.Jugar();
        }

Problemas propuestos


  1. Plantear una clase Club y otra clase Socio.
    La clase Socio debe tener los siguientes atributos privados: nombre y la antigüedad en el club (en años). En el constructor pedir la carga del nombre y su antigüedad. La clase Club debe tener como atributos 3 objetos de la clase Socio. Definir una responsabilidad para imprimir el nombre del socio con mayor antigüedad en el club. 

domingo, 15 de septiembre de 2013

24 Constructor de la clase

En C# podemos definir un método que se ejecute inicialmente y en . Este método se lo llama constructor.
El tiene las siguientes características:
  • Tiene el mismo nombre de la clase.
  • Es el primer método que se ejecuta.
  • Se ejecuta en forma automática.
  • No puede retornar datos.
  • Se ejecuta una única vez.
  • Un constructor tiene por objetivo inicializar .


Problema 1:

Se desea guardar los sueldos de 5 operarios en un vector. Realizar la creación y carga del vector en el constructor.


Programa:

using System;
using System.Collections.;
using System.Linq;
using System.Text;

namespace PruebaConstructor1
{
    class Operarios
    {
        private int[] sueldos;

        public Operarios()
        {
            sueldos=new int[5];
            for(int f = 0; f < sueldos.Length; f++) 
            {
                Console.Write("Ingrese el sueldo:");
                string linea = Console.ReadLine();
                sueldos[f]=int.Parse(linea);
            } 
        }

        public void Imprimir() 
        {
            for(int f = 0; f < sueldos.Length; f++)
            {
                Console.WriteLine(sueldos[f]);
            }
            Console.ReadKey();
        }

        static void Main(string[] args)
        {
            Operarios op = new Operarios();
            op.Imprimir();
        }
    }
}

Como podemos ver es el mismo problema que resolvimos cuando vimos vectores. La diferencia es que hemos sustituido el método Cargar con el constructor:

        public Operarios()
        {
            sueldos=new int[5];
            for(int f = 0; f < sueldos.Length; f++) 
            {
                Console.Write("Ingrese el sueldo:");
                string linea = Console.ReadLine();
                sueldos[f]=int.Parse(linea);
            } 
        }

Como la clase se llama Operarios el constructor tiene el mismo nombre, no disponemos la void ya que el constructor no puede retornar datos.
La ventaja de plantear un constructor en lugar de definir un método con cualquier nombre es que se llamará en forma automática cuando se crea un objeto de esta clase:

            Operarios op = new Operarios();

Cuando se crea el objeto op se llama al método constructor.
Finalmente llamamos al método imprimir:

            op.Imprimir();



Problema 2:

Plantear una clase llamada Alumno y definir como atributos su nombre y su edad. En el constructor realizar la carga de datos. Definir otros dos métodos los datos ingresados y un mensaje si es mayor o no de edad (edad >=18)

Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PruebaConstructor2
{
    class Alumno
    {
        private string nombre;
        private int edad;

        public Alumno() 
        {
            Console.Write("Ingrese nombre:");
            nombre = Console.ReadLine();
            Console.Write("Ingrese edad:");
            string linea = Console.ReadLine();
            edad=int.Parse(linea);
        }

        public void Imprimir()
        {
            Console.WriteLine("Nombre:"+nombre);
            Console.WriteLine("Edad:"+edad);
        }

        public void EsMayorEdad() 
        {
            if (edad >= 18) 
            {
                Console.Write(nombre+" es mayor de edad.");
            }
            else 
            {
                Console.Write(nombre+" no es mayor de edad.");
            }
        }

        static void Main(string[] args)
        {
            Alumno alumno1 = new Alumno();
            alumno1.Imprimir();
            alumno1.EsMayorEdad();
            Console.ReadKey();
        }
    }
}
Declaramos la clase Persona, sus dos atributos y definimos el constructor con el mismo nombre de la clase:

    class Alumno
    {
        private string nombre;
        private int edad;

        public Alumno() 
        {
            Console.Write("Ingrese nombre:");
            nombre = Console.ReadLine();
            Console.Write("Ingrese edad:");
            string linea = Console.ReadLine();
            edad=int.Parse(linea);
        }

En la main el constructor se llama en forma automática cuando creamos un objeto de la clase Alumno:

        static void Main(string[] args)
        {
            Alumno alumno1 = new Alumno();

Los otros dos métodos deben llamarse por su nombre y en el orden que necesitemos:

            alumno1.Imprimir();
            alumno1.EsMayorEdad();



Problemas propuestos


  1. Confeccionar una clase que represente un empleado. Definir como atributos su nombre y su sueldo. En el constructor cargar los atributos y luego en otro método imprimir sus datos y por último uno que imprima un mensaje si debe pagar impuestos (si el sueldo supera a 3000)
  2. Implementar la clase operaciones. Se deben cargar dos valores enteros en el constructor, calcular su suma, resta, multiplicación y división, cada una en un método, imprimir dichos resultados. 

23 Matrices irregulares o dentadas

C# nos permite crear irregulares o dentadas. Se dice que una matriz es irregular si la cantidad de elementos de cada fila varía. Luego podemos imaginar una matriz irregular:

matriz irregular


Como podemos ver la fila cero tiene reservado dos espacios, la fila uno reserva espacios y la última fila reserva espacio para tres componentes.


La sintaxis para declarar una matriz irregular es:

int [][] mat;

Primero creamos la cantidad de dejando vacío el espacio que indica la cantidad de columnas:

mat=new int[3][];

Luego debemos ir creando cada fila de la matriz indicando la cantidad de elementos de la respectiva fila:

mat[0]=new int[2];
mat[1]=new int[4];
mat[2]=new int[3];

Luego la forma para acceder a sus componentes debe ser utilizando corchetes abiertos y cerrados para cada índice:

mat[0][0]=120;

Dará un error si queremos cargar la tercer componente de la fila cero (esto debido a que no existe):

mat[0][2]=230;

Luego si queremos saber la cantidad de filas que tiene la matriz:

Console.Write(mat.Length);

Si queremos saber la cantidad de elementos de una determinada fila:

Console.Write("Cantidad de elementos de la fila 0:"+mat[0].Length);
Console.Write("Cantidad de elementos de la fila 1:"+mat[1].Length);
Console.Write("Cantidad de elementos de la fila 2:"+mat[2].Length);



Problema 1:

Confeccionaremos un programa que permita crear una matriz irregular y luego imprimir la matriz en .

Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MatrizIrregular1
{
    class MatrizIrregular1
    {
        private int[][] mat;
    
        public void Cargar() 
        {
            Console.Write("Cuantas fila tiene la matriz:");
            string linea=Console.ReadLine();
            int filas=int.Parse(linea);
            mat=new int[filas][];
            for(int f = 0; f < mat.Length; f++)
            {
                Console.Write("Cuantas elementos tiene la fila " + f + ":");
                linea = Console.ReadLine();
                int elementos=int.Parse(linea);
                mat[f]=new int[elementos];            
                for(int c = 0; c < mat[f].Length; c++) 
                {
                    Console.Write("Ingrese componente:");
                    linea=Console.ReadLine();
                    mat[f][c]=int.Parse(linea);
                }
            }
        }
    
        public void Imprimir() 
        {
            for(int f = 0; f < mat.Length; f++)
            {
                for(int c = 0; c < mat[f].Length; c++)
                {
                    Console.Write(mat[f][c]+" ");
                }
                Console.WriteLine();
            }
            Console.ReadLine();
        }
    
        static void Main(string[] args)
        {
            MatrizIrregular1 ma = new MatrizIrregular1();
            ma.Cargar();
            ma.Imprimir();
        }
    }
}

Primero creamos la cantidad de filas que tendrá la matriz (en los corchetes columnas no disponemos valor):

            Console.Write("Cuantas fila tiene la matriz:");
            string linea=Console.ReadLine();
            int filas=int.Parse(linea);
            mat=new int[filas][];

Dentro del primer for pedimos que ingrese la cantidad de elementos 
que tendrá cada fila y utilizamos el operador new nuevamente, pero en 
este caso se están creando cada fila de la matriz (C# trata a cada fila 
como un vector):

                Console.Write("Cuantas elementos tiene la fila " + f + ":");
                linea = Console.ReadLine();
                int elementos=int.Parse(linea);
                mat[f]=new int[elementos];            

Dentro del for interno hacemos la carga de las componentes propiamente dicho de la matriz (podemos ir cargando cada fila a medida que las vamos creando):

                for(int c=0;c < mat[f].Length;c++) 
                {
                    Console.Write("Ingrese componente:");
                    linea=Console.ReadLine();
                    mat[f][c]=int.Parse(linea);
                }

Luego imprimimos la matriz en forma teniendo cuidado las condiciones que disponemos en cada for.
El primer for se repite tantas veces como filas tiene la matriz: f<mat.Length y
el for interno se repite tantas veces como elementos tiene la fila que estamos procesando c<mat [f].Length:

            for(int f = 0; f < mat.Length; f++)
            {
                for(int c = 0; c < mat[f].Length; c++)
                {
                    Console.Write(mat[f][c]+" ");
                }
                Console.WriteLine();
            }



Problemas propuestos


  1. Confeccionar una clase para administrar una matriz irregular de 5 filas y 1 columna la primer fila, 2 columnas la segunda fila y así sucesivamente hasta 5 columnas la última fila (crearla sin la intervención del operador)
    Realizar la carga por teclado e imprimir posteriormente.
  2. Confeccionar una clase para administrar los días que han faltado los 3 empleados de una empresa.
    Definir un vector de 3 elementos de tipo string para cargar los nombres y una matriz irregular para cargar los días que han faltado cada empleado (cargar el número de día que faltó)
    Cada fila de la matriz representan los días de cada empleado.
    Mostrar los empleados con la cantidad de inasistencias.
    Cuál empleado faltó menos días. 

22 Matrices y vectores paralelos

Dependiendo de la complejidad del problema podemos necesitar el empleo de vectores y paralelos.



Problema 1:

Se tiene la siguiente información:
· Nombres de 4 empleados.
· Ingresos en concepto de sueldo, por cada empleado, en los últimos 3 meses.
Confeccionar el programa para:
a) Realizar la carga de la información mencionada.
b) Generar un vector que contenga el ingreso acumulado en sueldos en los últimos 3 meses para cada empleado.
c) Mostrar por pantalla el total pagado en sueldos a empleados en los últimos 3 meses
d) Obtener el nombre del empleado que tuvo el mayor ingreso acumulado

vectores y matrices paralelos



Programa:

using System;
using System.Collections.;
using System.Linq;
using System.Text;

namespace Matriz9
{
    class Matriz9
    {
        private string[] empleados;
        private int[,] sueldos;
        private int[] sueldostot;

        public void Cargar() 
        {
            empleados=new String[4];
            sueldos=new int[4,3];
            for(int f = 0; f < empleados.Length; f++)
            {
                Console.Write("Ingrese el nombre del empleado:");
                empleados[f]=Console.ReadLine();
                for(int c = 0; c < sueldos.GetLength(1); c++) 
                {
                    Console.Write("Ingrese sueldo:");
                    string linea;
                    linea = Console.ReadLine();
                    sueldos[f,c]=int.Parse(linea);
                }
            }
        }

        public void CalcularSumaSueldos()
        {
            sueldostot = new int[4];
            for (int f = 0; f < sueldos.GetLength(0); f++)
            {
                int suma = 0;
                for (int c = 0; c < sueldos.GetLength(1); c++)
                {
                    suma = suma + sueldos[f,c];
                }
                sueldostot[f] = suma;
            }
        }

        public void ImprimirTotalPagado() 
        {
         Console.WriteLine("Total de sueldos pagados por empleado.");
            for(int f = 0; f < sueldostot.Length; f++) 
            {
                Console.WriteLine(empleados[f]+" - "+sueldostot[f]);
            }
        }

        public void EmpleadoMayorSueldo() 
        {
            int may=sueldostot[0];
            string nom=empleados[0];
            for(int f = 0; f < sueldostot.Length; f++) 
            {
                if (sueldostot[f] > may) 
                {
                    may=sueldostot[f];
                    nom=empleados[f];
                }
            }
            Console.WriteLine("El empleado con mayor sueldo es "+ nom + " que tiene un sueldo de "+may);
        }

        static void Main(string[] args)
        {
            Matriz9 ma = new Matriz9();
            ma.Cargar();
            ma.CalcularSumaSueldos();
            ma.ImprimirTotalPagado();
            ma.EmpleadoMayorSueldo();
            Console.ReadKey();
        }
    }
}

Para este problema lo primero que hacemos es definir una matriz donde se almacenarán los sueldos mensuales de cada empleado, un vector de tipo string donde almacenaremos los nombre de cada empleado y finalmente definimos un vector paralelo a la matriz donde almacenaremos la suma de cada fila de la matriz:

        private string[] empleados;
        private int[,] sueldos;
        private int[] sueldostot;

En el método de cargar inicializamos el vector con los nombres de los empleados y la matriz paralela donde se almacenan los últimos tres sueldos (previo a cargar procedemos a crear el vector y la matriz):

            empleados=new String[4];
            sueldos=new int[4,3];
            for(int f = 0; f < empleados.Length; f++)
            {
                Console.Write("Ingrese el nombre del empleado:");
                empleados[f]=Console.ReadLine();
                for(int c = 0; c < sueldos.GetLength(1); c++) 
                {
                    Console.Write("Ingrese sueldo:");
                    string linea;
                    linea = Console.ReadLine();
                    sueldos[f,c]=int.Parse(linea);
                }
            }

El método sumar sueldos crea el vector donde se almacenará la suma de cada fila de la matriz. Mediante dos for recorremos toda la matriz y sumamos cada fila:

            sueldostot = new int[4];
            for (int f = 0; f < sueldos.GetLength(0); f++)
            {
                int suma = 0;
                for (int c = 0; c < sueldos.GetLength(1); c++)
                {
                    suma = suma + sueldos[f,c];
                }
                sueldostot[f] = suma;
            }

El método ImprimirTotalPagado tiene por objetivo mostrar los dos vectores (el de nombre de los empleados y el que almacena la suma de cada fila de la matriz):

         Console.WriteLine("Total de sueldos pagados por empleado.");
            for(int f = 0; f < sueldostot.Length; f++) 
            {
                Console.WriteLine(empleados[f]+" - "+sueldostot[f]);
            }

Por último para obtener el nombre del empleado con mayor sueldo acumulado debemos inicializar dos variables auxiliares con el primer elemento del vector de empleados y en otra auxiliar guardamos la primer componente del vector sueldostot:

            int may=sueldostot[0];
            string nom=empleados[0];
            for(int f = 0; f < sueldostot.Length; f++) 
            {
                if (sueldostot[f] > may) 
                {
                    may=sueldostot[f];
                    nom=empleados[f];
                }
            }
            Console.WriteLine("El empleado con mayor sueldo es "+ nom + " que tiene un sueldo de "+may);



Problemas propuestos


  1. Se desea saber la temperatura media trimestral de cuatro paises. Para ello se tiene como dato las temperaturas medias mensuales de dichos paises.
    Se debe ingresar el nombre del país y seguidamente las tres temperaturas medias mensuales.
    Seleccionar las estructuras de datos adecuadas para el almacenamiento de los datos en memoria.
    a - Cargar por teclado los nombres de los paises y las temperaturas medias mensuales.
    b - Imprimir los nombres de las paises y las temperaturas medias mensuales de las mismas.
    c - Calcular la temperatura media trimestral de cada país.
    c - Imprimr los nombres de las provincias y las temperaturas medias trimestrales.
    b - Imprimir el nombre de la provincia con la temperatura media trimestral mayor. 

21 Matrices (cantidad de filas y columnas)

Como hemos visto para definir y crear la utilizamos la siguiente sintaxis:

int[,] mat;

Creación:

mat=new int[3,4];

matrices son objetos en C# disponemos de un método llamado GetLength que le pasamos como parámetro la dimension y nos retorna el valor de dicha dimensión.

Si queremos saber la cantidad de que tiene la matriz debemos llamar al método GetLength con el valor cero:

Console.WriteLine("Cantidad de filas de la matriz:" + mat.GetLength(0));

Si queremos saber la cantidad de columnas luego:

Console.WriteLine("Cantidad de columnas de la matriz:" + mat.GetLength(1));

La primer dimensión son la cantidad de filas y la segunda dimensión son la cantidad de columnas de la matriz.



Problema 1:

Crear una matriz de n * m filas (cargar n y m por teclado) Imprimir la matriz y la última fila.

Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Matriz5
{
    class Matriz5
    {
        private int[,] mat;

        public void Cargar() 
        {
            Console.Write("Cuantas fila tiene la matriz:");
            string linea;
            linea=Console.ReadLine();
            int filas=int.Parse(linea);
            Console.Write("Cuantas columnas tiene la matriz:");
            linea=Console.ReadLine();
            int columnas=int.Parse(linea);
            mat=new int[filas,columnas];
            for(int f = 0; f < mat.GetLength(0); f++) 
            {
                for (int c = 0; c < mat.GetLength(1); c++)
                {
                    Console.Write("Ingrese componente:");
                    linea = Console.ReadLine();
                    mat[f,c] = int.Parse(linea);
                }
            }
        }

        public void Imprimir() 
        {
            for(int f = 0; f < mat.GetLength(0); f++)
            {
                for(int c = 0; c < mat.GetLength(1); c++)
                {
                    Console.Write(mat[f,c]+" ");
                }
                Console.WriteLine();
            }
        }

        public void ImprimirUltimaFila() 
        {
         Console.WriteLine("Ultima fila");
            for(int c = 0; c < mat.GetLength(1); c++)
            {
                 Console.Write(mat[mat.GetLength(0)-1,c]+" ");
            }
        }

        static void Main(string[] args)
        {
            Matriz5 ma = new Matriz5();
            ma.Cargar();
            ma.Imprimir();
            ma.ImprimirUltimaFila();
            Console.ReadKey();
        }
    }
}

En este ejemplo que se ejecute el programa el tamaño de la matriz lo define el usuario, para ello ingresamos por teclado dos enteros y seguidamente procedemos a crear la matriz con dichos valores:

            Console.Write("Cuantas fila tiene la matriz:");
            string linea;
            linea=Console.ReadLine();
            int filas=int.Parse(linea);
            Console.Write("Cuantas columnas tiene la matriz:");
            linea=Console.ReadLine();
            int columnas=int.Parse(linea);
            mat=new int[filas,columnas];
Ahora las estructuras repetitivas las acotamos preguntando a la misma matriz la cantidad de filas y la cantidad de columnas:

            for(int f = 0; f < mat.GetLength(0); f++) 
            {
                for (int c = 0; c < mat.GetLength(1); c++)
                {
                    Console.Write("Ingrese componente:");
                    linea = Console.ReadLine();
                    mat[f,c] = int.Parse(linea);
                }
            }
El algoritmo de impresión es idéntico al visto anteriormente con la modificación de las condiciones de los for:
            for(int f = 0; f < mat.GetLength(0); f++)
            {
                for(int c = 0; c < mat.GetLength(1); c++)
                {
                    Console.Write(mat[f,c]+" ");
                }
                Console.WriteLine();
            }

la última fila debemos disponer un valor fijo en el subíndice de la fila (en este caso no podemos disponer un número fijo sino preguntarle a la misma matriz la cantidad de filas y restarle uno ya que las filas comienzan a numerarse a partir de cero: mat[mat.GetLength(0)-1,c]

También la condición del for debemos preguntar a la matriz la cantidad de columnas mat.GetLength(1):

         Console.WriteLine("Ultima fila");
            for(int c = 0; c < mat.GetLength(1); c++)
            {
                 Console.Write(mat[mat.GetLength(0)-1,c]+" ");
            }



Problema 2:

Crear una matriz de n * m filas (cargar n y m por teclado) Imprimir el mayor elemento y la fila y columna donde se almacena.

Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Matriz6
{
    class Matriz6
    {
        private int[,] mat;

        public void Cargar() 
        {
            Console.Write("Cuantas fila tiene la matriz:");
            string linea;
            linea=Console.ReadLine();
            int filas=int.Parse(linea);
            Console.Write("Cuantas columnas tiene la matriz:");
            linea=Console.ReadLine();
            int columnas=int.Parse(linea);
            mat=new int[filas,columnas];
            for(int f = 0; f < mat.GetLength(0); f++)
            {
                for(int c = 0; c  mayor) 
                    {
                        mayor=mat[f,c];
                        filamay=f;
                        columnamay=c;
                    }
                }
            }
            Console.WriteLine("El elemento mayor es:"+mayor);
            Console.WriteLine("Se encuentra en la fila:"+filamay+ " y en la columna: "+columnamay);
            Console.ReadLine();
        }

        static void Main(string[] args)
        {
            Matriz6 ma = new Matriz6();
            ma.Cargar();
            ma.ImprimirMayor();
        }
    }
}

Para obtener el mayor elemento de la matriz y la fila y columna donde se ubica debemos inicializar una variable mayor con el elemento de la fila cero y columna cero (esto lo hacemos suponiendo que en dicha posición se almacena el mayor):

         int mayor=mat[0,0];
         int filamay=0;
         int columnamay=0;

Luego mediante dos for recorremos todos los elementos de la matriz y cada vez que encontramos un elemento mayor al actual procedemos a actualizar la variable mayor y la posición donde se almacena:

            for(int f = 0; f < mat.GetLength(0); f++)
            {
                for(int c = 0; c < mat.GetLength(1); c++) 
                {
                    if (mat[f,c] > mayor) 
                    {
                        mayor=mat[f,c];
                        filamay=f;
                        columnamay=c;
                    }
                }
            }



Problemas propuestos


  1. Crear una matriz de n * m filas (cargar n y m por teclado) Intercambiar la primer fila con la segundo. Imprimir luego la matriz.
  2. Crear una matriz de n * m filas (cargar n y m por teclado) Imprimir los cuatro valores que se encuentran en los vértices de la misma (mat[0][0] etc.) 

20 Estructura de datos tipo matriz

Una matriz es una de datos que permite almacenar un CONJUNTO de datos del MISMO tipo.

Con un único nombre se define la matriz y de DOS subíndices hacemos referencia a cada elemento de la misma (componente)

matriz


Hemos graficado una matriz de 3 filas y 5 columnas. Para hacer referencia a cada elemento debemos indicar primero la fila y luego la columna, por ejemplo en la componente 1,4 se almacena el valor 97.
En este ejemplo almacenamos valores enteros. elementos de la matriz deben ser del mismo tipo (int, float, string etc.)

Las filas y columnas comienzan a numerarse a partir de cero, similar a los vectores.



Problema 1:

Crear una matriz de 3 filas por 5 columnas con elementos de tipo int, cargar sus componentes y luego imprimirlas.


Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Matriz1
{
    class Matriz1
    {
        private int[,] mat;

        public void Cargar() 
        {
            mat=new int[3,5];
            for(int f = 0;f < 3;f++) 
            {
                for(int c = 0;c < 5;c++)
                {
                    Console.Write("Ingrese componente:");
                    string linea;
                    linea = Console.ReadLine();
                    mat[f,c]=int.Parse(linea);
                }
            }
        }

        public void Imprimir() 
        {
            for(int f = 0;f < 3;f++) 
            {
                for(int c = 0;c < 5;c++) 
                {
                    Console.Write(mat[f,c]+" ");
                }
                Console.WriteLine();
            }
            Console.ReadKey();
        }  

        static void Main(string[] args)
        {
            Matriz1 ma = new Matriz1();
            ma.Cargar();
            ma.Imprimir();
        }
    }
}

Para definir una matriz debemos disponer una coma dentro de los corchetes:

        private int[,] mat;

De esta forma el compilador de C# puede diferenciar los vectores de las matrices.
Para crear la matriz, es decir hacer la reserva de espacio de todas sus componentes debemos utilizar el operador new y mediante dos subíndices indicamos la cantidad de filas y columnas que tendrá la matriz:

            mat=new int[3,5];

Luego debemos pasar a cargar sus 15 componentes (cada fila almacena 5 componentes y tenemos 3 filas)
Lo más cómodo es utilizar un for anidado, el primer for que incrementa el contador f lo utilizamos para recorrer las filas y el contador interno llamado c lo utilizamos para recorrer las columnas.
que se repite en forma completa el for interno se carga una fila completa, primero se carga la fila cero en forma completa, luego la fila uno y finalmente la fila 2.
Siempre que accedemos a una posición de la matriz debemos disponer dos subíndices que hagan referencia a la fila y columna mat[f,c]):

            for(int f = 0;f < 3;f++) 
            {
                for(int c = 0;c < 5;c++)
                {
                    Console.Write("Ingrese componente:");
                    string linea;
                    linea = Console.ReadLine();
                    mat[f,c]=int.Parse(linea);
                }
            }

la matriz de forma similar utilizamos dos for para acceder a cada elemento de la matriz:

            for(int f = 0;f < 3;f++) 
            {
                for(int c = 0;c < 5;c++) 
                {
                    Console.Write(mat[f,c]+" ");
                }
                Console.WriteLine();
            }

Cada vez que se ejecuta  vueltas del for interno tenemos en pantalla 
una fila completa de la matriz, por eso pasamos a ejecutar un salto de 
línea (con esto logramos que en pantalla los datos aparezcan en forma 
matricial):

                Console.WriteLine();



Problema 2:

Crear y cargar una matriz de 4 filas por 4 columnas. Imprimir la diagonal principal.
              x    -    -    -
              -    x    -    -
              -    -    x    -
              -    -    -    x

Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Matriz2
{
    class Matriz2
    {
        private int[,] mat;

        public void Cargar() 
        {
            mat=new int[4,4];
            for(int f = 0; f < 4; f++) 
            {
                for(int c = 0; c<4; c++) 
                {
                    Console.Write("Ingrese componente:");
                    string linea;
                    linea = Console.ReadLine();
                    mat[f, c] = int.Parse(linea);
                }
            }
        }

        public void ImprimirDiagonalPrincipal() 
        {
            for(int k = 0; k < 4; k++) 
            {
                Console.Write(mat[k,k]+" ");
            }
            Console.ReadKey();
        }

        static void Main(string[] args)
        {
            Matriz2 ma = new Matriz2();
            ma.Cargar();
            ma.ImprimirDiagonalPrincipal();
        }
    }
}

La definición, creación y carga de la matriz no varían con el ejemplo anterior.
Para imprimir la diagonal principal de la matriz lo más conveniente es utilizar un for que se repita 4 veces y disponer como subíndice dicho contador (los elementos de la diagonal principal coinciden los valores de la fila y columna):

            for(int k = 0; k < 4; k++) 
            {
                Console.Write(mat[k,k]+" ");
            }



Problema 3:

Crear y cargar una matriz de 3 filas por 4 columnas. Imprimir la primer fila. Imprimir la última fila e imprimir la primer columna.

Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Matriz3
{
    class Matriz3
    {
        private int[,] mat;

        public void Cargar() 
        {
            mat=new int[3,4];
            for(int f = 0; f < 3; f++) 
            {
                for(int c = 0; c < 4; c++) 
                {
                    Console.Write("Ingrese componente:");
                    string linea;
                    linea = Console.ReadLine();
                    mat[f,c]=int.Parse(linea);
                }
            }
        }

        public void PrimerFila() 
        {
         Console.WriteLine("Primer fila de la matriz:");
            for(int c = 0; c < 4; c++) 
            {
                Console.WriteLine(mat[0,c]);
            }
        }

        public void UltimaFila() 
        {
         Console.WriteLine("Ultima fila de la matriz:");
            for(int c = 0; c < 4; c++) 
            {
                Console.WriteLine(mat[2,c]);
            }
        }

        public void PrimerColumna() 
        {
         Console.WriteLine("Primer columna:");
            for(int f = 0; f < 3; f++) 
            {
                Console.WriteLine(mat[f,0]);
            }
        }

        static void Main(string[] args)
        {
            Matriz3 ma = new Matriz3();
            ma.Cargar();
            ma.PrimerFila();
            ma.UltimaFila();
            ma.PrimerColumna();
            Console.ReadKey();
        }
    }
}

Creamos una matriz de 3 filas y 4 columnas:

            mat=new int[3,4];

Luego de cargarla el primer método que codificamos es el que imprime la primer fila. Disponemos un for para recorrer las columnas, ya que la fila siempre será la cero. Como son cuatro los elementos de la primer fila el for se repite esta cantidad de veces:

         Console.WriteLine("Primer fila de la matriz:");
            for(int c = 0; c < 4; c++) 
            {
                Console.WriteLine(mat[0,c]);
            }

Para imprimir la última fila el algoritmo es similar, disponemos un for que se repita 4 veces y en el subíndice de la fila disponemos el valor 2 (ya que la matriz tiene 3 filas):

         Console.WriteLine("Ultima fila de la matriz:");
            for(int c = 0; c < 4; c++) 
            {
                Console.WriteLine(mat[2,c]);
            }

Para imprimir la primer columna el for debe repetirse 3 veces ya que la matriz tiene 3 filas. Dejamos constante el subíndice de la columna con el valor cero:

         Console.WriteLine("Primer columna:");
            for(int f = 0; f < 3; f++) 
            {
                Console.WriteLine(mat[f,0]);
            }



Problemas propuestos


  1. Crear una matriz de 2 filas y 5 columnas. Realizar la carga de componentes por columna (es decir primero ingresar toda la primer columna, luego la segunda columna y así sucesivamente)
    Imprimir luego la matriz.

19 Vectores (ordenamiento con vectores paralelos)

Cuando se tienen vectores y se ordena uno de ellos tener la precaución de intercambiar los elementos de los vectores paralelos.


Problema 1:

Confeccionar un programa que permita cargar los nombres de 5 alumnos y sus notas respectivas. Luego ordenar las mayor a menor. Imprimir las notas y los nombres de los alumnos.

Programa:

using System;
using System.Collections.;
using System.Linq;
using System.Text;

namespace PruebaVector16
{
    class PruebaVector16
    {
        private string[] nombres;
        private int[] notas;

        public void Cargar() 
        {
            nombres=new string[5];
            notas=new int[5];
            Console.WriteLine("Carga de nombres y notas");
            for(int f=0;f < nombres.Length;f++) 
            {
                Console.Write("Ingese el nombre del alumno:");
                nombres[f]=Console.ReadLine();
                Console.Write("Ingrese la nota del alumno:");
                string linea;
                linea = Console.ReadLine();
                notas[f]=int.Parse(linea);
            }
        }

        public void Ordenar()
        {
            for (int k = 0; k < notas.Length; k++)
            {
                for (int f = 0; f < notas.Length - 1 - k; f++)
                {
                    if (notas[f] < notas[f + 1])
                    {
                        int auxnota;
                        auxnota = notas[f];
                        notas[f] = notas[f + 1];
                        notas[f + 1] = auxnota;
                        string auxnombre;
                        auxnombre = nombres[f];
                        nombres[f] = nombres[f + 1];
                        nombres[f + 1] = auxnombre;
                    }
                }
            }
        }

        public void Imprimir() 
        {
            Console.WriteLine("Nombres de alumnos y notas de mayor a menor");
            for(int f=0;f < notas.Length;f++) 
            {
                Console.WriteLine(nombres[f] + " - " + notas[f]);
            }
            Console.ReadLine();
        }

        static void Main(string[] args)
        {
            PruebaVector16 pv = new PruebaVector16();
            pv.Cargar();
            pv.Ordenar();
            pv.Imprimir();
        }
    }
}

Definimos los dos vectores:

        private string[] nombres;
        private int[] notas;

Creamos los dos vectores paralelos con cinco elementos cada uno:

            nombres=new string[5];
            notas=new int[5];

En el proceso de ordenamiento dentro de los dos for verificamos si debemos los elementos del vector notas:

            for (int k = 0; k < notas.Length; k++)
            {
                for (int f = 0; f < notas.Length - 1 - k; f++)
                {
                    if (notas[f] < notas[f + 1])
                    {

En el caso que la nota de la posición 'f' sea menor a de la posición siguiente 'f+1' procedemos a intercambiar las notas:

                        int auxnota;
                        auxnota = notas[f];
                        notas[f] = notas[f + 1];
                        notas[f + 1] = auxnota;

y simultánemamente procedemos a intercambiar los elementos del vector paralelo (con esto logramos que los dos vectores continuen siendo vectores paralelos):

                        string auxnombre;
                        auxnombre = nombres[f];
                        nombres[f] = nombres[f + 1];
                        nombres[f + 1] = auxnombre;

Como vemos utilizamos dos auxiliares distintos porque los elementos de los dos vectores son de distinto tipo (int y string)

Si deseamos ordenar alfabéticamente la condición dependerá del vector nombres.



Problemas propuestos


  1. Cargar en un vector los nombres de 5 paises y en otro vector paralelo la cantidad de habitantes del mismo. Ordenar alfabéticamente e imprimir los resultados. Por último ordenar con respecto a la cantidad de habitantes (de mayor a menor) e imprimir nuevamente.

18 Vectores (ordenamiento)

El ordenamiento de un vector se logra intercambiando las componentes de manera que:

vec[0] <= vec[1] <= vec[2] etc.

El contenido de la componente vec[0] sea menor o igual al contenido de la componente vec[1] y así sucesivamente.
Si se cumple lo dicho anteriormente decimos que el vector está ordenado de menor a mayor. Igualmente podemos ordenar un vector de mayor a menor.
Se puede ordenar tanto vectores con componentes de tipo int, float como string. En este último caso el ordenamiento es alfabético.



Problema 1:

Se debe crear un vector donde almacenar 5 sueldos. Ordenar el vector sueldos de menor a mayor.

ordenamiento de un vector


Esta primera aproximación tiene por objetivo analizar los intercambios de elementos dentro del vector.
El algoritmo consiste en si la primera componente es mayor a la segunda, en caso que la condición sea verdadera, intercambiamos los contenidos de las componentes.

Vamos a suponer que se ingresan los siguientes valores por teclado:

1200
750
820
550
490

En este ejemplo: ¿es 1200 mayor a 750? La respuesta es verdadera, por lo tanto intercambiamos el contenido de la componente 0 con el de la componente 1.
Luego comparamos el contenido de la componente 1 con el de la componente 2: ¿Es 1200 mayor a 820?
La respuesta es verdadera entonces intercambiamos.
Si hay 5 componentes hacer 4 comparaciones, por eso el for se repite 4 veces.

Generalizando: si el vector tiene N componentes hay N-1 comparaciones.



Cuando  f = 0  f = 1  f  = 2  f = 3
  
  750  750  750  750
  1200  820  820  820
  820  1200  550  550
  550  550  1200  490
  490  490  490  1200


Podemos ver cómo el valor del vector desciende a la última componente. Empleamos una variable auxiliar (aux) para el proceso de intercambio:

aux=sueldos[f];
sueldos[f]=sueldos[f+1];
sueldos[f+1]=aux;

Al salir del for en este ejemplo el contenido del vector es el siguiente:

750
820
550
490
1200

Analizando el algoritmo podemos comprobar que el elemento mayor del vector se ubica ahora en el último lugar.

Podemos definir otros vectores con distintos valores y comprobar que siempre el elemento mayor queda al final.

Pero todavía con este algoritmo no se ordena un vector. Solamente está ordenado el último elemento del vector.

Ahora bien, con los 4 elementos que nos quedan podemos hacer el mismo proceso visto anteriormente, con lo cual quedará ordenado otro elemento del vector. Este proceso lo repetiremos hasta que quede ordenado por completo el vector.

Como debemos el mismo algoritmo podemos englobar todo el bloque en otra estructura repetitiva.


ordenamiento de un vector


Realicemos una prueba del siguiente algoritmo:

Cuando k = 0
  f = 0  f = 1  f = 2  f = 3
  750  750  750  750
  1200  820  820  820
  820  1200  550  550
  550  550  1200  490
  490  490  490  1200
  
Cuando k = 1
  f = 0  f = 1  f  = 2  f = 3
  750  750  750  750 
  820  550  550  550
  550  820  490  490
  490  490  820  820
  1200  1200  1200  1200

Cuando k = 2
  f = 0  f = 1  f  = 2  f = 3
  550  550  550  550
  750  490  490  490
  490  750  750  750
  820  820  820  820
  1200  1200  1200  1200


Cuando k = 3
  f = 0  f = 1  f  = 2  f = 3
  490  490  490  490
  550  550  550  550
  750  750  750  750
  820  820  820  820
  1200  1200  1200  1200

¿Porque repetimos 4 veces el for externo?

Como sabemos que se repite en forma completa el for interno queda ordenada una componente del vector. A primera vista diríamos que deberíamos repetir el for externo la cantidad de componentes del vector, en este ejemplo el vector sueldos tiene 5 componentes.

Si observamos, cuando quedan dos elementos por ordenar, al ordenar uno de ellos queda el otro automáticamente ordenado (podemos imaginar que si tenemos un vector con 2 elementos no se requiere el for externo, porque este debería repetirse una única vez)

Una última consideración a este ALGORITMO de ordenamiento es que los elementos que se van ordenando continuamos comparándolos.

Ejemplo: En la primera ejecución del for interno el valor 1200 queda ubicado en la posición 4 del vector. En la segunda ejecución comparamos si el 820 es mayor a 1200, lo cual seguramente será falso.
Podemos concluir que la primera vez debemos hacer para este ejemplo 4 comparaciones, en la segunda ejecución del for interno debemos hacer 3 comparaciones y en general debemos ir reduciendo en uno la cantidad de comparaciones.

Si bien el algoritmo planteado funciona, un algoritmo más eficiente, que se deriva del anterior es el plantear un for interno con la siguiente estructura: (f=0 ; f<4-k; f++)
Es decir restarle el valor del contador del for externo.


Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PruebaVector13
{
    class PruebaVector13
    {
        private int[] sueldos;

        public void Cargar() 
        {
            sueldos=new int[5];
            for(int f=0;f < sueldos.Length;f++) 
            {
                Console.Write("Ingrese el sueldo:");
                string linea = Console.ReadLine();
                sueldos[f]=int.Parse(linea);
            }
        }

        public void Ordenar()
        {
            for (int k = 0; k < 4; k++)
            {
                for (int f = 0; f < 4 - k; f++)
                {
                    if (sueldos[f] > sueldos[f + 1])
                    {
                        int aux;
                        aux = sueldos[f];
                        sueldos[f] = sueldos[f + 1];
                        sueldos[f + 1] = aux;
                    }
                }
            }
        }

        public void Imprimir() 
        {
            Console.WriteLine("Sueldos ordenados de menor a mayor.");
            for(int f=0;f < sueldos.Length;f++) 
            {
                Console.WriteLine(sueldos[f]);
            }
            Console.ReadKey();
        }

        static void Main(string[] args)
        {
            PruebaVector13 pv = new PruebaVector13();
            pv.Cargar();
            pv.Ordenar();
            pv.Imprimir();
        }
    }
}

También podemos ordenar vectores cuyas componentes sean de tipo String. Para esto no podemos utilizar el operador > sino debemos utilizar un método de la clase String:

string cad1="juan";
string cad2="analia";
if (cad1.CompareTo(cad2)>0)
{
    Console.Write(cad1 + " es mayor alfabéticamente que " + cad2);
}

El método CompareTo retorna un valor mayor a cero si cad1 es mayor alfabéticamente. En este ejemplo cad1 tiene un valor alfabéticamente mayor a cad2, luego el CompareTo retorna un valor mayor a cero.

Si los dos string son exactamente iguales el método CompareTo retorna un cero, y finalmente si cad1 es menor alfabéticamente retorna un valor menor a cero.



Problema 2:

Definir un vector donde almacenar los nombres de 5 paises. Confeccionar el algoritmo de ordenamiento alfabético.

Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PruebaVector14
{
    class PruebaVector14
    {
        private string[] paises;

        public void Cargar() 
        {
            paises=new string[5];
            for(int f=0;f < paises.Length;f++) 
            {
                Console.Write("Ingrese el nombre del pais:");
                paises[f]=Console.ReadLine();
            }
        }

        public void Ordenar()
        {
            for (int k = 0; k < 4; k++)
            {
                for (int f = 0; f < 4 - k; f++)
                {
                    if (paises[f].CompareTo(paises[f + 1])>0)
                    {
                        string aux;
                        aux = paises[f];
                        paises[f] = paises[f + 1];
                        paises[f + 1] = aux;
                    }
                }
            }
        }

        public void Imprimir() 
        {
         Console.WriteLine("Paises ordenados en forma alfabética:");
            for(int f=0;f < paises.Length;f++) 
            {
                Console.WriteLine(paises[f]);
            }
            Console.ReadKey();
        }


        static void Main(string[] args)
        {
            PruebaVector14 pv = new PruebaVector14();
            pv.Cargar();
            pv.Ordenar();
            pv.Imprimir();
        }
    }
}

Definimos un vector de tipo string:

        private string[] paises;

Lo creamos indicando que almacenará cinco elementos:

            paises=new string[5];

Procedemos a cargar el vector:

            for(int f=0;f < paises.Length;f++) 
            {
                Console.Write("Ingrese el nombre del pais:");
                paises[f]=Console.ReadLine();
            }

Para el ordenamiento utilizamos el método CompareTo para verificar si tenemos que intercambiar las componentes:

                    if (paises[f].CompareTo(paises[f + 1])>0)

En el caso que si tenemos que intercambiarla utilizamos un auxilir de tipo string:

                        string aux;
                        aux = paises[f];
                        paises[f] = paises[f + 1];
                        paises[f + 1] = aux;



Problemas propuestos


  1. Cargar un vector de n elementos de tipo entero. Ordenar posteriormente el vector.

17 Vectores (mayor y menor elemento)

Es una actividad común la búsqueda del mayor y de un vector, lo mismo que su posición.

vector


El mayor elemento es el 820 y se encuentra en la posición nº 2.



Problema 1:

Confeccionar un programa que permita cargar los nombres de 5 operarios y sus sueldos respectivos. Mostrar el sueldo mayor y el nombre del operario.

Programa:

using System;
using System.Collections.;
using System.Linq;
using System.Text;

namespace PruebaVector11
{
    class PruebaVector11
    {
        private string[] nombres;
        private float[] sueldos;

        public void Cargar() 
        {
            nombres=new string[5];
            sueldos=new float[5];
            for(int f=0;f < nombres.Length;f++) 
            {
                Console.Write("Ingrese el nombre del empleado:");
                nombres[f] = Console.ReadLine();
                Console.Write("Ingrese el sueldo:");
                string linea;
                linea = Console.ReadLine();
                sueldos[f]=float.Parse(linea);
            }
        }

        public void MayorSueldo() 
        {
            float mayor;
            int pos;
            mayor=sueldos[0];
            pos=0;
            for(int f=1;f < nombres.Length;f++) 
            {
                if (sueldos[f] > mayor) 
                {
                    mayor=sueldos[f];
                    pos=f;
                }
            }
            Console.WriteLine("El empleado con sueldo mayor es "+nombres[pos]);
            Console.WriteLine("Tiene un sueldo:"+mayor);
            Console.ReadKey();
        }

        static void Main(string[] args)
        {
            PruebaVector11 pv = new PruebaVector11();
            pv.Cargar();
            pv.MayorSueldo();
        }
    }
}

Definimos los dos vectores paralelos donde almacenaremos los nombres y los sueldos de los operarios:

        private string[] nombres;
        private float[] sueldos;

Creamos los dos vectores y procedemos a cargar sus elementos:

            nombres=new string[5];
            sueldos=new float[5];
            for(int f=0;f < nombres.Length;f++) 
            {
                Console.Write("Ingrese el nombre del empleado:");
                nombres[f] = Console.ReadLine();
                Console.Write("Ingrese el sueldo:");
                string linea;
                linea = Console.ReadLine();
                sueldos[f]=float.Parse(linea);
            }

Para obtener el mayor sueldo y el nombre del operario realizar los siguientes pasos:
Inicializamos una variable mayor con la primer componente del vector sueldos:


            mayor=sueldos[0];

Inicializamos una variable pos con el 0, ya que decimos primeramente que el mayor es la primer componente del vector:

            pos=0;

Recorremos las componentes del vector que faltan analizar, o sea, de la 1 a la 4:

            for(int f=1;f < nombres.Length;f++) 

Accedemos a cada componente para controlar si lo que tiene la variable mayor:

                if (sueldos[f] > mayor) 

En caso de ser verdadera la condición asignamos a la variable mayor este nuevo valor sueldos[f]

                    mayor=sueldos[f];

y a la variable pos le cargamos la variable f que indica la componente que estamos analizando:

                    pos=f

Cuando salimos de la estructura repetitiva imprimimos la variable mayor que contiene el mayor sueldo y el nombre del operario conociendo la posición del mayor sueldo imprimimos el elemento que ocupa la posición que indica la variable pos en el vector paralelo:

  Console.WriteLine("El empleado con sueldo mayor es "+nombres[pos]);
  Console.WriteLine("Tiene un sueldo:"+mayor);



Problemas propuestos


  1. Cargar un vector de n elementos. imprimir el menor y un mensaje si se repite dentro del vector.