[ Foro de Pascal ]

eliminar secuencia

11-Feb-2014 19:55
Invitado (LuisOtero)
16 Respuestas

Hola estoy intentando ayuda acerca de un programa de la facultad.
hace referencia a como eliminar de un arreglo de enteros los elementos que aparezcan repetidos secuencialmente , dejando solo los primeros de la secuencia
A1=111 2 1 5 66
Aresultante = 1 2 1 5 6

me gustaria me ayudaran, el tema de arreglos me esta costando y en especial este ejercicio.gracias al foro por la ayuda.


12-Feb-2014 22:57
Nacho Cabanes (+83)

Tu pregunta no es clara: Supongo que debería haber espacios en tu array inicial:

A1=1 1 1 2 1 5 6 6

de modo que tendría 8 elementos, en vez de ser 5 elementos, alguno de los cuales tiene varias veces la misma cifra (111, 66).

Como comentaba en hilo muy reciente del foro, para eliminar un valor de un array necesitas dos cosas:

- Mover todos los valores siguientes a su posición anterior. Por ejemplo, para quitar el primer 1 redundante, que está en la segunda posición, moverías el siguiente 1 de la posición 3 a la 2, y después el 2 de la cuarta posición a la tercera y así sucesivamente.

- Con eso, tu array se ha convertido en (1 1 2 1 5 6 6 [6]), de modo que necesitas un "contador" que indique cual es el tamaño de tu array, porque ahora "no está lleno": tiene capacidad para 8 datos, pero sólo 7 son datos "de verdad", el último dato es falso, porque hemos borrado uno. Por tanto, necesitas algo como "cantidadDeDatos := cantidadDeDatos - 1") para saber que el array no contiene todos los datos que podría contener, sino que hay "huecos" al final, porque tu array realmente debería ser (1 1 2 1 5 6 6 [hueco no usado])

Por tanto, la lógica de tu programa sería:


para cada valor i desde 2 hasta n:
    si dato[i] = dato[i-1] entonces
        borrar dato[i]


(donde la rutina de borrado sería la que te he comentado antes)


13-Feb-2014 12:51
Invitado (LuisOtero)

Hola profesor.
entiendo lo que me explicaste, queria preguntarte algo al respecto en tu seudocodigo:


para cada valor i desde 2 hasta n:
    si dato[i] = dato[i-1] entonces
        borrar dato[i]

borrar dato[i]


seria entonces poner:


 dato[i-1]:=dato[i];      ???


ahora lo que mencionas del contador bueno entiendo que el N es el numero de elementos de mi arreglo inicial, entonces me sugieres algo como:


longArray:=N;


y luego en:


para cada valor i desde 2 hasta n:
    si dato[i] = dato[i-1] entonces
      inicie
        dato[i-1]:=dato[i];      ???
       longArray:=N-1;
       fin


y entonces luego para imprimir el nuevo arreglo seria:


for i:=1 to longArray do
  write(dato[i];


por favor corrigeme o si es correcto lo que te expongo.

bien si asi estuviera bien el ejercicio anterior, queria preguntar respecto a este ejercicio, si se tratara no de eliminar los elementos repetidos de una secuencia, sino encontrar e imprimir la secuencia mas larga consecutiva de elementos en un arreglo, me podrias dar una idea por favor de como poder realizarlo, muchisimas gracias profesor eres muy amable y desconocia este genial foro.


14-Feb-2014 00:27
Nacho Cabanes (+83)

Se va acercando, pero para borrar un elemento de un array tienes que desplazar todos los que le siguen.

Mira, te he preparado un ejemplo básico aquí:
http://www.aprendeaprogramar.com/fuentes/view.php?t=4


14-Feb-2014 11:47
Invitado (LuisOtero)

hola Nacho, gracias por respornder.
profesor estuve mirando tu ejemplo , y he comparado lo que yo te planteaba y en lo unico que noto tengo quiza mal es cuando disminuyo el tamaño, es decir:


para cada valor i desde 2 hasta n:
    si dato[i] = dato[i-1] entonces
      inicie
        dato[i-1]:=dato[i];      ???
       longArray:=N-1;
       fin


deberia sacar longArray:=N-1; osea


para cada valor i desde 2 hasta n:
    si dato[i] = dato[i-1] entonces
            dato[i-1]:=dato[i];      //cierra el if
       longArray:=N-1;
       fin


lo que no entiendo es cuando me dices que :
"tienes que desplazar todos los que le siguen."
no se supone que ya lo estoy haciendo cuando hago:


dato[i-1]:=dato[i];    


pues viendo tu ejemplo del link no noto algo diferente al mio profesor, podrias hacermelo ver, disculpa si no lo veo y gracias por tu ayuda, estoy aprendiendo mas que en clase.


14-Feb-2014 14:45
Nacho Cabanes (+83)

No. Tu estás moviendo un único dato hacia atrás una única posición.

En general, para borrar un único elemento de un array, necesitas un "for", como en el ejemplo que te he puesto.

En tu caso, que quieres borrar varios datos, toda esa estructura del ejemplo tiene que estar incluida dentro de otro "for", para aplicar esa estructura de forma repetitiva.


23-Feb-2014 21:27
Invitado (LuisOtero)

buenas, profesor osea que al codigo,


para cada valor i desde 2 hasta n:
    si dato[i] = dato[i-1] entonces
            dato[i-1]:=dato[i];      
  longArray:=N-1;



debo agregar un for superior: ESTE FOR DEBE IR ENTRE 1 Y N ???????


para cada valor i desde 1 hasta n 
 inicie
   para cada valor i desde 2 hasta n:
     inicie
        si dato[i] = dato[i-1] entonces
             dato[i-1]:=dato[i];      
         longArray:=N-1;
     fin
fin


estaria bien asi profesor, si no por favor corrigeme y muchisimas gracias.


24-Feb-2014 22:45
Invitado (LuisOtero)

Disculpa profesor es que me quede con la duda y es que he visto que has respondido a compañeros y quiza mi post no lo viste, por eso lo repito disculpame, y gracias

debo agregar un for superior:  ????? ESTE FOR DEBE IR ENTRE 1 Y N ???????


para cada valor i desde 1 hasta n 
inicie 
  para cada valor i desde 2 hasta n: 
    inicie 
       si dato[i] = dato[i-1] entonces 
            dato[i-1]:=dato[i];       
        longArray:=N-1; 
    fin 
fin 


estaria bien asi profesor, si no por favor corrigeme y muchisimas gracias.


25-Feb-2014 19:38
Nacho Cabanes (+83)

Sí, esa la idea se acerca, pero tienes el "para" y el "si" intercambiados: la idea de borrar repetidos es


para cada dato
    si es igual al siguiente
        borrar ese dato


que se convertiría en algo como


para cada valor j desde 1 hasta n 
    si dato[j] = dato[j-1] entonces 
        para cada valor i desde j+1 hasta n: 
           dato[i-1]:=dato[i];       
        longArray:=N-1; 


No lo he revisado, pero espero que entiendas la diferencia con tu planteamiento. De igual modo, verás que no puedes usar un único índice "i", sino dos distintos.

También deberás llevar cuidado con los límites, porque cada vez que eliminas un elemento, estás cambiando el valor de "n", y tu "for" externo deberá recorrer un valor menos, algo que normalmente no está permitido en Pascal (sí en otros lenguajes como C), así que quizá debas plantear el bucle externo como un "while" o un "repeat".


27-Feb-2014 21:07
Invitado (LuisOtero)

hola profesor nacho
disculpame pero es que no me sale este ejercicio, intento hacer lo que tu me sugieres y mi programa es este, pero por favor ayudame a ver cual es mi problema por el que el resultado no es el esperado, ayudame ya no se que hacer mas con este ejercicio y mira que le he dedicado tiempo, aunque es verdad que he aprendido mucho con tus sugerencias.


program repet;
uses crt;

Type
TipoTabla=Array[1..30] of integer;
var
i, j,long,tamanio,tam : integer;
tabla : TipoTabla;
begin
clrscr;
Writeln('introduzca la dimension del array:');
readln(tam);
writeln('digite los valores para el array :');
For i:=1 to tam do
readln(tabla[i]);

i:=1;
 while i<=tam DO
   begin
    if tabla[i]=tabla[i+1] then
     for j:=i+1 to tam-1 do
	   begin
	   tabla[j-1]:=tabla[j];
        long:=tam-1;
	   end;
           
    i:=i+1;	  
	end; 
	 
for i:=1 to long do
  write(tabla[i]:2);
readln;
end.


por favor revizal en ejecucion para los datos del ejemplo que te di al inicio y ayudame a resolver por que esta mal, gracias muchas gracias


01-Mar-2014 11:43
Nacho Cabanes (+83)

Veamos...

Por una parte, tienes una variable "tamanio" que no usas, la elimino.

Por otra parte, "tam" es el tamaño del array, pero haces que "i" vaya hasta i+1, de modo que puedes desbordar el array.

Además, disminuyes la longitud dentro del "for", de modo que eliminas "casi todos los elementos" de golpe, en vez de uno a uno.

También, si "tam" es el tamaño máximo, sería más razonable que fuera una constante, y que los cambios los hicieras en "long", que representa la longitud actual (imagino). Jugar con dos variables que quieren decir casi lo mismo y que tienen nombres tan parecidos es peligroso.

Un detalle que no te comenté en la respuesta anterior es que, como un dato puede repetirse varias veces (como ese 1 1 1), es peligroso usar un "for", porque quizá no debas avanzar al elementos siguiente hasta que hayas eliminado varios datos repetitivos, no sólo uno. Aun así, se puede hacer con un "for", pero acordándote de hacer "i := i -1" si has encontrado un dato repetitivo, de modo que vuelvas a la misma posición, para comprobar si el siguiente dato también es repetitivo.

Finalmente, para hacer pruebas repetitivas es preferible usar datos prefijados, en vez de pedir siempre al usuario, de modo que las pruebas se puedan hacer rápido, así que voy a crear un array prefijado con tus datos iniciales...

Una solución completa a partir de tu fuente podría ser así:


program borrarRepetitivos;

uses crt;


(*type
    TipoTabla=Array[1..30] of integer;

var
    i, j,long,tam : integer;
    tabla : TipoTabla;*)

const
    tam = 8;
    tabla : array[1..tam] of integer =
        (1, 1, 1, 2, 1, 5, 6, 6);

var 
    i, j, long: integer;

begin
    (*clrscr;
    Writeln('introduzca la dimension del array:');
    readln(tam);
    writeln('digite los valores para el array :');
    for i:=1 to tam do
        readln(tabla[i]);
    *) 

    i := 1;
    long := tam;
    while i < long do
    begin
        if tabla[i] = tabla[i+1] then  (* Dos iguales ? *)
            begin
            for j := i+1 to long-1 do            
                tabla[j-1]:=tabla[j];  (* Retrocedo los siguientes *)
            long := long-1;            (* Tengo un dato menos      *)
            i := i - 1;   (* Y vuelvo a mirar el elemento actual   *)
            end;
        i := i+1;  (* Si he terminado con este elemento, paso al prox *)
    end; 

    for i := 1 to long do   (* Finalmente, muestro el resultado *)
        write(tabla[i]:2);
     
    readln; (* Pausa hasta pulsar Intro *)
end.



01-Mar-2014 20:47
Invitado (LuisOtero)

ok profesor solo una  pregunta a tu codigo:

cuando haces:
i := i - 1;   (* Y vuelvo a mirar el elemento actual   *)
esta instruccion por cada pasada del while se convierte en cero siempre verdad y luego con

la instruccion que le sigue:
i := i+1;  (* Si he terminado con este elemento, paso al prox *)

este nuevo i( siempre sera 1 en la entrada de cada nuevo while verdad?

por favor si estoy en lo correcto hazmelo saber es que segun mi seguimiento realmente el i con el que entramos al while siempre sera 1 solo que ira hasta una long distinta en cada pasada del mismo?

gracias por corregirme o por si estoy en lo correcto para quedar mas tranquilo de que entendi todo el programa.????

otra cosa profesor esta seria la forma mas optima o habria otra posibilidad mas eficiente si es asi por favor intenta indicarmelo, y muchiimas gracias esta labor que haces no tiene precio es unica en las web sites no he visto un foro parecido y tan completo, estoy siguiendo tu nuevo curso a pesar de que ya voy mas adelante pero es que esta magistral, gracias.


01-Mar-2014 23:34
Invitado (LuisOtero)

disculpa ademas se me paso preguntarte si en tu planteamiento estas:
dejando solo los primeros de la secuencia o los ultimos, por lo que he podido seguir creo que dejas el ultimo de la secuencia,, pero no tengo la certeza por eso espero me respondas ademas del anterior post a este, gracias muy amable


02-Mar-2014 20:22
Nacho Cabanes (+83)

No vale 0 y 1: i va aumentando de 1 en 1, de modo que de la posición 2 pasas a la 3, y de esa a la 4. Pero no se puede hacer eso "a ciegas", porque si hay varios datos iguales seguidas podrías saltarte alguno. Por eso, si has encontrado un duplicado, debes volver atrás para volver si el valor que habías mirado todavía está repetido (porque haya 3 o más valores seguidos).

En mi planteamiento conservo el primero de cada secuencia repetitiva y elimino los que le siguen (pruébalo, haciendo que te muestre el estado en cada pasada).


03-Mar-2014 12:50
Invitado (LuisOtero)

Hola profesor nacho.
profesor disculpa pero no comprendo, Y TE PIDO POR FAVOR MIRES PASO A PASO MI SEGUIMIENTO PARA QUIE PUEDAS VER SI ESTOY EN LO CORRECTO O DONDE FALLO O ESTOY MAL INTERPRETANDO LA SOLLUCION ... , inicialmente antes de entrar al while i:=1, ok


 if tabla[1]= tabla[2] then (true) para el ejemplo inicial del post:   1 1 1 2 1 5 6 6 ( long:=8)
   begin
          for j := i+1 to long-1 do            
             tabla[j-1]:=tabla[j];  (* Retrocedo los siguientes *)
          {finalizado este for j, obtendriamos el array:  1   1   2   1   5   6   6}
        long := long-1;       long:=8-1=7)
        i := i - 1;   {aqui es donde yo te digo, este i:=1-1:=0
    end;
i := i+1; y ahora i:=0+1= 1 {0 de cuando salimos del if e hicimos i:=i-1}


osea que aqui entro al while nuevamente con i:=1 y no con i:=2 hasta este punto estoy haciendo algo mal en mi seguimiento al programa? bien, lo que yo noto es que  cuando se acaba la secuencia  es decir en nuestro ejemplo cuando termino la secuencia de unos  en ese caso si no entrariamos al if y entonces en ese caso si que i:=i+1 valdria 2 y la lista que estariamos analizando en este punto seria la lista : 1  2   1   5   6   6 y ese i:=2 seria desde el elemento 2,  Y la long:= 6
si sigo encuentro que hasta no llegar al primer 6 de la lista de long=6 no entraria al if, en este caso segun mi seguimiento hasta el momento, mi i vale i:=5, con lo cual miraria ahora if tabla[5]=tabla[6] y encontraria que 6 es igual a 6 y entraria al for del j donde obtendria la nueva lista del array: 1  2   1   5  6 y mi longitud ahora seria de long:=5 y ahora haria i:=i-1 , osea mi i ahora valdria 5-1:=4 COSA QUE NO ENTIENDO EN ESTE CASO PARA QUE SE DISMINUYE SI A LA FINAL LA INSTRUCCION SIGUIENTE QUE SE HARIA ES i:=i+1, osea que valdria ahora i:=5, en otras palabras en este punto para que sirve:   i := i - 1;   (* Y vuelvo a mirar el elemento actual   *)
POR FAVOR DIME DONDE ESTOY HACIENDO MAL MI SEGUIMIENTO POR QUE LA VERDAD NO LO VEO, gracias por ayudarme para mi es importante este seguimiento, mas que me funcione el ejercicio.


06-Mar-2014 19:52
Invitado (LuisOtero)

profesor no se si hayas podido ver mi ultimo post de este ejercicio, gracias por tu atencion y ayuda


15-Mar-2014 12:35
Nacho Cabanes (+83)

Si tienes dudas con la traza, siempre queda el recurso de que sea el ordenador quien la haga por ti, mostrándote en cada paso cual es el contenido del array.

Por ejemplo, puedes modificar el programa anterior, para que muestre el estado del array tras cada pasada. Podría ser algo como:


program borrarRepetitivos;
 
uses crt;
 
const
    tam = 8;
    tabla : array[1..tam] of integer =
        (1, 1, 1, 2, 1, 5, 6, 6);

procedure mostrar(tabla: array of integer; cantidad: integer);
var
    i: integer;
begin
    for i := 0 to cantidad-1 do
        write(tabla[i]:2);
    writeLn;
end;
 
var 
    i, j, long: integer;
 
begin
    i := 1;
    long := tam;

    while i < long do
    begin
        writeLn('Posicion: ', i); 
        mostrar(tabla, long);
        if tabla[i] = tabla[i+1] then  (* Dos iguales ? *)
            begin
            for j := i+1 to long-1 do            
                tabla[j-1]:=tabla[j];  (* Retrocedo los siguientes *)
            long := long-1;            (* Tengo un dato menos      *)
            i := i - 1;   (* Y vuelvo a mirar el elemento actual   *)
            
            mostrar(tabla, long);
            end;
        
        i := i+1;  (* Si he terminado con este elemento, paso al prox *)
    end; 
 
    mostrar(tabla, long);
 
    readln; (* Pausa hasta pulsar Intro *)
end.


que daría como resultado


Posicion: 1
 1 1 1 2 1 5 6 6
 1 1 2 1 5 6 6
Posicion: 1
 1 1 2 1 5 6 6
 1 2 1 5 6 6
Posicion: 1
 1 2 1 5 6 6
Posicion: 2
 1 2 1 5 6 6
Posicion: 3
 1 2 1 5 6 6
Posicion: 4
 1 2 1 5 6 6
Posicion: 5
 1 2 1 5 6 6
 1 2 1 5 6
 1 2 1 5 6


Hay un comportamiento desconcertante (¿un bug?) en Turbo Pascal 7 y en Free Pascal: si pasas un array como parámetro, da por sentado que empieza en cero, y no en el valor que tú hayas usado realmente (1, en mi caso). Por eso, el "for" de la función comienza en 0 y acaba en 7, a pesar de ser un array con índices "1..8".

Pero lo importante es que puedes hacer que sea el compilador quien te muestre en pantalla cualquiera de las variables que tú estabas analizando en papel, y así encontrar dónde está la parte que quizá no hubieras entendido o que se esté comportando de forma incorrecta.






(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.)