[ Foro de Pascal ]

comprimir arreglo.

22-Mar-2012 23:46
Luis Torres (+12)
9 Respuestas

Hola, un saludo a todos. Mi pregunta es: Si tengo un arreglo con los siguientes datos:
   Arreglo ('regla','lapiz','lapiz','regla','borrador','regla')
¿Qué algoritmo debo seguir, o programa en Pascal, que me permita modificarlo y conseguir que el arreglo guarde cada elemento sin su repetición?. O sea, obtener el siguiente Arreglo:
   Arreglo ('regla','lapiz','borrador','','','')

Les agradecería muchísimo que me pudieran ayuda.
Saludos.


23-Mar-2012 11:11
oscar gomez

el programa que expones es bastante interesante por que es distinto eliminar digamoslo asi de un array los elementos repetidos cuando estos son cadenas (string)a cuando son esteros porejemplo, supongo yo claro!.
te dejo mi idea para eliminar los repetidos pero en un vector de enteros, se que es distinto, pero no se si lo que deseabas es el algoritmo para quitar repetidos para cualquier caso enteros o string ,te dejo mi algoritmo que quiza pueda ayudarte:


conRepetidos =array[1..long1];

sinRepetidos =array[1..long2];



procedimiento quitarRepetidos(conRepetidos,var sinRepetidos,long1,var long2);



var i,j,k :integer;

     repetido:boolean;



begin

  sinRepetidos(1):=conRepetidos(1);

  i:=2;

  k;=1;

  while i<=long1 do

    begin

      repetido:=false;

      j:=1;

      while ((j<=k) and (not  repetido))  do

          begin

              if conRepetidos[i] = sinRepetidos[j]   then

                   repetido:=true

                else

                     j:=j+1;

            end;{del while}

        if repetido =false  then

             begin

                k:=k+1;

                sinRepetidos[k]:=conRepetidos[i];

              end;

           inc(i);

     end; { del 1er while }

   long2:=k;



end.

         

Espero haberte ayudado al menos a dislumbrar una idea.
hasta luego Luis.



23-Mar-2012 23:56
Nacho Cabanes (+32)

Yo haría algo como esto: comparar cada dato con todos los posteriores; si aparece repetido en otra posición, lo borras

para cada i desde 1 hasta n - 1
 para cada j desde i+1 hasta n
   si dato[i] = dato[j] eliminar dato[j]

Donde ese "eliminar" supone mover "un paso hacia adelante" todos los elementos que hay a partir de esa posición, así como disminuir el tamaño (el contador de posiciones usadas del array):

para cada k desde j hasta n - 1
 dato[j] = dato[j+1]
n = n - 1



24-Mar-2012 21:28
Luis Torres (+12)

Gracias a Oscar y al prof. Nacho por sus respuestas, son muy amables en responder. Voy a organizar mejor mi mente para hacerlo, porque me enredo mucho tratando de implementarlo.
Saludos.


25-Mar-2012 05:02
Luis Torres (+12)

Sí, efectivamente mi pregunta la formulé para resolver el problema de los países, sus ventas y su media. Hice la compresión usando otra forma que se me ocurrió. Creo que está bien, pero en caso de empate saldrá el país que está de primero en el arreglo (el programa calcula el país con la media más alta). Las medias son datos tipo real, he leído que hay problemas cuando en los programas se comparan datos de tipo real, me gustaría que el profesor me esclareciera un poco sobre este tema de comparación de números reales.
Aquí les dejo el código del programa con mi solución. Espero que sea de utilidad. Hay que revisarlo mucho a ver si realmente hace lo que se pide. Acá está:

program ventas_internacionales;
uses crt;
const numvendedores=6;
     
type
    cadena=string[30];
    rango=1..numvendedores;
    vendedor=record
      nombre,pais:cadena;
      ventas: integer;
     end;
     vendedores=array[rango] of vendedor;


var
    v:vendedores;
    paises, p: array[rango] of cadena;
    total: array[rango] of integer;
    media: array[rango] of real;
    numpaises: array[rango] of integer;
    cant: integer;
    i,j:integer;
    Maximo: real;
    indice: integer;
   

begin
                            (* Leemos los datos *)
   clrscr;
   writeln;writeln;writeln;writeln;
   for i:=1 to numvendedores do
     begin
       writeln('introduzca el nombre del vendedor: ');
       readln(v[i].nombre);
       writeln('introduzca el pais del vendedor: ');
       readln(v[i].pais);
       writeln('ventas totales en un periodo determinado en ese pais :');
       readln(v[i].ventas);
     end;



           (* Pasamos al arreglo p el campo pais del arreglo v con su repeticion  *)

   for i:=1 to numvendedores do
      p[i]:= v[i].pais;



           (* sustituimos los paises repetidos por la cadena vacía, o sea por ''  *)

   for i:=1 to numvendedores do
     begin
       for j:= i+1 to numvendedores do
         if p[j]= p[i] then
            p[j]:='';
     end;



            (* Llenamos el arreglo paises con los paises unicos, sin repetidos  *)

   cant:= 0;
   for i:= 1 to numvendedores do
     begin
       if p[i]<>'' then
         begin
           cant:= cant+1;
           paises[cant]:= p[i];
         end;
     end;


   (* Llenamos el arreglo numpaises con la cantidad de repeticiones de cada pais *)

    for i:=1 to cant do        {inicializamos numpaises}
       numpaises[i]:= 0;

    for i:=1 to cant do
        for j:=1 to numvendedores do
          if paises[i] = v[j].pais then
            inc(numpaises[i]);



    (* Asignamos el total de la suma de ventas de cada pais a total *)

    for i:= 1 to cant do
      total[i]:=0;

    for i:= 1 to cant do
      for j:=1 to numvendedores do
        if paises[i] = v[j].pais then
           total[i]:= total[i] + v[j].ventas;
 


    (* Calculamos la media de cada pais *)

    for i:=1 to cant do
       media[i]:= total[i]/numpaises[i];



    (* La clave de esta solucion ha sido el uso de arreglos paralelos, *)
    (* el subindice de cada arreglo es el elemento comun; asi, numpaises1*)
    (* tendra las repeticiones de paises1 y, media1 la media de paises1, *)
    (* lo mismo con total1. Ahora lo que falta es buscar el indice para  *)
    (* el cual la media es la mayor. Esto sera lo que vamos a hacer a *)
    (* continuacion *)
   
    Maximo:= media[1];
    indice:= 1;
    for i:= 2 to cant do
      if media[i] > Maximo then
        begin
          Maximo:= media[i];
          indice:= i;
        end;
   
   


                          (* Mostramos los resultados *)

      clrscr;
       GOTOXY(17,7);
       WRITELN(' ********  DATOS DE ENTRADA ******** ');
       WRITELN;
       GOTOXY(2,9);
       WRITELN(' Nombre      Pais        ventas');
       GOTOXY(2,10);
       WRITE('_______    _______       _______ ');
       WRITELN;WRITELN;WRITELN;
       FOR i:=1 to numvendedores do
        begin
          GOTOXY(2,10+i);
          WRITE(v[i].nombre);
          GOTOXY(13,10+i);
          WRITE(v[i].pais);
          GOTOXY(30,10+i);
          WRITE(v[i].ventas);
        end;
      WRITELN;WRITELN;WRITELN;WRITELN;
      writeln('Pais ganador: ',paises[indice]);

  readkey;
end.  

De todas maneras lo pondré como archivo adjunto.
Saludos y gracias.


26-Mar-2012 21:56
Nacho Cabanes (+32)

Efectivamente, comparar números reales con "=" es peligroso, porque se almacenan con una cierta pérdida de precisión, y podría llegar a ocurrir que nunca se diera que "x = 10.0" (por ejemplo).

Es algo que depende de cada lenguaje y de cada compilador, pero en general suele ser preferible comparar si está dentro de un rango: "if x > 9.9 and x < 10.1 then ..." en vez de comparar con un valor exacto.


26-Mar-2012 23:30
Luis Torres (+12)

¿Y entonces cómo hallaría los países con igual "media", si esta variable tiene que ser real?. Gracias por la respuesta, profesor Nacho y Saludos.


30-Mar-2012 17:33
Nacho Cabanes (+32)

Perdona, Luis, se me había pasado este mensaje sin contestar.

Para hallar dos países con igual media, compara los valores tal cual (o incluso los valores redondeados a un número entero o a un valor con pocas cifras decimales).

Como comparas dos campos "media", que son del mismo tipo, debería funcionar sin problemas.

El riesgo tiene que ver más con expresiones como

if x = 7.53 then ...

porque puede ocurrir que la variable x sea un real de simple precisión y 7.53 se tome como un valor de doble precisión, o viceversa, de modo que exista una diferencia en los redondeos al comparar.


31-Mar-2012 20:08
Luis Torres (+12)

¿Cómo es ese de valor real de simple precisión y valor real de doble precisión?, ¿cómo hago para redondear a dos cifras decimales?. Saludos.


01-Apr-2012 10:16
Nacho Cabanes (+32)

En Pascal, eso no debería preocuparte: sólo existe un tipo de datos "real", que en equipos antiguos correspondía a un número real de simple precisión, y en equipos modernos a uno de doble precisión, como puedes leer aquí:

http://wiki.freepascal.org/real

(Esta transparencia para el usuario tiene el problema de que ficheros binarios creados con una versión de Pascal no se lean correctamente con otra).

En C y la mayoría de los lenguajes que derivan de él, sí se distingue entre "float" (real de simple precisión) y double (de doble precisión):

http://www.nachocabanes.com/csharp/curso/csharp02b.php


Para redondear, en Pascal tienes funciones como Round, que redondea al entero más cercano:

http://www.freepascal.org/docs-html/rtl/system/round.html

Trunc, que quita los decimales:

http://www.freepascal.org/docs-html/rtl/system/trunc.html

o incluso "Int" (no en todos los compiladores), cuyo resultado sigue siendo un número real, pero sin los decimales:

http://www.freepascal.org/docs-html/rtl/system/int.html

pero todos ellos dejan el resultado sin ningún decimal. Si quieres redondear a (por ejemplo) dos decimales, hay al menos un par de alternativas: en primer lugar, a mano, podrías hacer:

resultado := round(numero*100) / 100;

En segundo lugar, en algún compilador moderno, como Free Pascal, tienes RoundTo:

http://www.freepascal.org/docs-html/rtl/math/roundto.html

http://www.freepascal.org/docs-html/rtl/math/simpleroundto.html






(No se puede continuar esta discusión porque tiene más de dos meses de antigüedad. Si tienes dudas parecidas, abre un nuevo hilo.)