style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">

Ejercicio (como) para volverse loco

Resolviendo una pregunta en otro lado llegue después de un par de iteraciones a una solución bastante extraña para resolver el siguiente problema:

"Crear un método que reemplace todas las letras L encontradas en HELLO WORLD con una x y que la x aparezca incrementada en cada ocurrencia de L"

Ejemplos:

Entrada: "HELLO WORLD"
Salida:  "HExxxO WORxxxD"
Entrada: "HELLO LAZY LIMBO WORLD"
Salida:  "HExxxO xxxAZY  xxxxIMBO WOxxxxxR"

Restricciones: Únicamente se pueden utilizar los siguiente métodos de la clase String:.length; .indexOf; y.substring(); y claro el resto del lenguaje ( for, while, operador + variables etc. ). Ninguna otra clase, ningún otro método.

Mi solución solo dos sentencias:

public static String replace( String in ){    
  //??
  //??
  return in;
}

Pff... para volverse loco.

Ahi se los dejo de tarea.

Update Le había puesto que regresaba XXX en unos y xxx en otros. Es siempre con la misma "x" ( cualquiera de las dos )

Mi error, corregido. Gracias wishmaster77 por notarlo.

EDIT: (ezamudio) Si piensan resolver el ejercicio, no vean todavía los comentarios, porque ya hay algunas soluciones ahí; primero resuélvanlo y luego ponen su solución en los comentarios, para compararla con las que ya están...

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

En un solo for

De hecho así lo pensé. En C puedes tener varias inicializaciones en la parte de inicialización. La alternativa es ( como ya pudiste ver ) sacrificar el indice y calcularlo siempre. Pero me hacía sentir sucio. jajaa

Por si alguién necesita traducción de la caricatura ahi va ( aunque no habrá explicación, exlicar XKCD le quita el chiste )


- nano? Los verdaderos programadores usan emacs
- Oye!, Los VERDADEROS programadores usan VIM
- Bueno, los VERDADEROS programadores usan ed
- NO los VERDADERES PROGRAMADORES usan cat
- Los verdaderos programadores usan una aguja imantada y una mano muy firme.
- Discúlpenme pero los VERDADEROS programadores usan Mariposas:

Abren sus manos y dejan que sus delicadas manos aleteen una vez..
... Las turbulencia de las ondas cambia el flujo de las corrientes de la atmosfera superior
... Que a su vez causan momentarias bolsas de aire a alta presión...
... Que actúan como lentes de desvían los rayos cósmicos entrantes, enfocándolos sobre el plato del disco duro y cambiando el bit necesario....


- Vaya!.. Pero bueno, por su puesto hay un comando en emacs para hacer eso... - Ahh si el viejo truco de C-x-M-x M-mariposa...
- Diablos emacs!

Real programmers

http://xkcd.com/378

Imagen de ezamudio

alt-text

cuando pongas un xkcd debes conservar el alt-text, siempre es parte del humor. Este dice algo de que los programadores de verdad configuran las variables necesarias al inicio del universo para que todo evolucione a que el disco tenga los datos que necesitan.

Lo había olvidado. Cuando

Lo había olvidado. Cuando hay alguno que no entiendo, el alt-text ( ahora que veo es el title ) me da la clave ( a veces ).

Otro

public class TestX {

   public static String replace(String cadena){
       String s = "";
       for (int l = cadena.toUpperCase().indexOf("L") ; l != -1 ; s+="x", s =

(cadena.charAt(l) != 76) ? s.toLowerCase() : s.toUpperCase(), cadena = cadena.substring(0,

l) + s + cadena.substring(l + 1, cadena.length()) , l = cadena.toUpperCase().indexOf("L") );
       return cadena;
   }

   public static String replace2(String cadena){
       for (String s = "", l = Integer.toString(cadena.toUpperCase().indexOf("L")) ;

Integer.valueOf(l) != -1 ; s+= "x", s = (cadena.charAt(Integer.valueOf(l)) != 76) ?

s.toLowerCase() : s.toUpperCase(), cadena = cadena.substring(0, Integer.valueOf(l)) + s +

cadena.substring(Integer.valueOf(l) + 1, cadena.length()) , l = Integer.toString

(cadena.toUpperCase().indexOf("L")) );
       return cadena;
   }

   public static void main(String[] arg) {
       System.out.println("HELLO WORLD");
       System.out.println(replace("HELLO WORLD"));
       System.out.println("HELLO LAZY LIMBO WORLD");
       System.out.println(replace("HELLO LAZY LIMBO WORLD"));
       System.out.println("HEllO lazy LIMBO WORlD");
       System.out.println(replace("HEllO lazy LIMBO WORlD"));
       System.out.println("HL");
       System.out.println(replace("HL"));
       System.out.println("H");
       System.out.println(replace("H"));
       System.out.println("l");
       System.out.println(replace("l"));
       System.out.println("lLl");
       System.out.println(replace("lLl"));
       System.out.println("");
       System.out.println(replace(""));
       //--
       System.out.println("HELLO WORLD");
       System.out.println(replace2("HELLO WORLD"));
       System.out.println("HELLO LAZY LIMBO WORLD");
       System.out.println(replace2("HELLO LAZY LIMBO WORLD"));
       System.out.println("HEllO lazy LIMBO WORlD");
       System.out.println(replace2("HEllO lazy LIMBO WORlD"));
       System.out.println("HL");
       System.out.println(replace2("HL"));
       System.out.println("H");
       System.out.println(replace2("H"));
       System.out.println("l");
       System.out.println(replace2("l"));
       System.out.println("lLl");
       System.out.println(replace2("lLl"));
       System.out.println("");
       System.out.println(replace2(""));
   }
}

1 sola linea (sentencia) iterativa

for (String x = "",  ci = ""; ci.length() < in.length(); ci+="x") if(in.charAt(ci.length())=='L') in = in.substring(0, ci.length())+(x=x+"x")+in.substring(ci.length()+1, in.length());

XD

Imagen de ezamudio

rafaelCacho

Eso no es una sola sentencia, son 3: El for, el if, y la asignación a la variable in. Ponerlo todo en la misma línea y omitir llaves no lo hace una sola sentencia.

Imagen de bimboso_d

Segunda ronda

He me parece bien, pero con las mismas restricciones?

2da ronda.

El problema con la segunda ronda está en que es muy difícil comparar si se corre en máquinas diferentes.

La única forma es comparando contra otras implementaciones corriendo en la misma máquina.

Lo que debe de funcionar más eficientemente debe de ser usando un StringBuilder, por que no se crean objetos innecesarios intermedios.

  public static String cambia( String entrada ) {
    StringBuilder sb = new StringBuilder();
    StringBuilder x = new StringBuilder();
    for( int i = 0 ; i < entrada.length() ; i++ ) {
      char c = entrada.charAt( i );
      if( c == 'L') {
        sb.append( x.append( 'X' ) );
      } else {
        sb.append( c );
      }
    }
    return sb.toString();
  }

Quizá una forma más eficiente que esa sería manejar a nivel de bits, quién sabe.

Ahí les dejo mi solución y la forma en que la comparé ( contra mi solución original );

class CambiaLs {
  public static void main( String ... args ) {
    //sumatoria de 100
    final String entrada = "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL";
    // primero ver si hacen lo mismo
    String got       = null;
    String expected = null;

    // invocar con  opcion -ea  ej. java -ea CambiaLs
    assert ( got = cambia(entrada) )
              .equals
          ( expected = replace(entrada) )
              : "Got " + got + " expected: "+expected;

    // Esta es la forma de usar closures en Java hoy en día.
    prueba( new Runnable() {
      public void run() {
        cambia( entrada ); // nueva version
      }
    });

    prueba( new Runnable() {
      public void run() {
        replace( entrada ); // version original
      }
    });
  }

  // Imprime cuantos ms.  se tarda en promedio
  // en ejecutar el Runnable "r" 10,000 veces
  public static void prueba( Runnable r ) {
    double sum = 0;
    int N = 10000;
    for( int i = 0 ; i < N; i++ ) {
      long start = System.currentTimeMillis();
      r.run();
      sum += System.currentTimeMillis() - start;
    }
    System.out.println( "Prom: " + ( sum / N) );
  }

   // nueva version son StringBulders
  public static String cambia( String entrada ) {
    StringBuilder sb = new StringBuilder();
    StringBuilder x = new StringBuilder();
    for( int i = 0 ; i < entrada.length() ; i++ ) {
      char c = entrada.charAt( i );
      if( c == 'L') {
        sb.append( x.append( 'X' ) );
      } else {
        sb.append( c );
      }
    }
    return sb.toString();
  }
 
  // mi version original  en dos sentancias.
  public static String replace( String in ){    
    String x = ""; // declaración 1 sentencia
    for( int i = 0;  ( i = in.indexOf('L',i)) > -1 ; in = in.substring(0,i++) + ( x=x+'X' ) + in.substring(i) ); // for 2da sentencia
    return in;
  }
}

Salida nueva version y version anterior ( promedio en millisegundos )

Prom: 0.0437
Prom: 1.0985
Imagen de ezamudio

bits?

Por el lado de performance, tal vez convenga manejar bytes directamente. Por el lado de memoria, puedes usar StringBuilder, o puedes crear un arreglo de caracteres exactamente del tamaño que vas a necesitar para la cadena resultante. Para ello necesitas darle dos pasadas a la cadena, primero contando las L's que hay para que calcules cuántas X's vas a meter en el resultado; y en la segunda pasada vas copiando de la cadena los fragmentos que no son L al nuevo arreglo de caracteres, a la vez de ir poniendo X's donde estaban las L's.

Imagen de ezamudio

warmup

Para benchmarks, recuerden hacer warmup primero (correr la función que van a probar, una vez, para que se compile en el JIT, y luego ya la corren tomando tiempo).

Imagen de luxspes

Primer intento en C# usando Aggregate (left fold)

Aqui va un intento rapido en C#, a partir de esto voy a ir bajando el numero de lineas de codigo:

 
 private string ReemplazarLPorX(string entrada)
        {
            var resultadoFinal = entrada.Aggregate(new Tuple<int, string>(1,""), (acc, next) =>
            {
                if (next == 'l')
                {
                    var replacement = new String('x', acc.Item1);
                    acc = new Tuple<int, string>(acc.Item1 + 1, acc.Item2 + replacement);
                }
                else {
                    acc = new Tuple<int, string>(acc.Item1, acc.Item2 + next);
                }
                return acc;
            });
            return resultadoFinal.Item2;
        }
Imagen de ezamudio

C#

El for de una línea debe jalar en C# también. A fin de cuentas nada más es inicializar una variable, concatenarla, y reasignar a la variable de la cadena dos subcadenas con la secuencia de X's.

Imagen de luxspes

C#: for

Si, definitivamente el for de una línea debe jalar en C# también. Pero como estado leyendo de Haskell, Scala, F# y las capacidades para programacion funcional en C#... pues no se me antoja usar un for ;-)

Solucion

Aqui mi solucion, disculpen pero apenas lei el post :p

public static String replace( String in ){
       for(String a=""; in.indexOf("L") != -1; )in = in.substring(0,in.indexOf("L")) + (a+="x") + in.substring(in.indexOf("L")+1);
       return in;
}

Con una linea :p

Saludos.

Editado--------
Creo que se parece a la solucion de rafaelCacho :p

Imagen de claudiaivette

Mi solución

Yo lo resolví en 3, o cuenta como 2??

String x="x";

for(int i=0;in.indexOf('l')!=-1;i++,x=x+"x")   
 in=in.substring(0,in.indexOf('l'))+x+in.substring(in.indexOf('l')+1);

Saludos

@claudiaivette Yeap, cuanta

@claudiaivette

Yeap, cuanta como 3

Ahora que si quitas la "i" que no estás usando y metes la declaración de x en la inicialización del for y el cuerpo del for dentro del incremento tendrás 1.

Imagen de claudiaivette

Si, tienes toda la razón...

Si, tienes toda la razón... ya me di cuenta revisando las soluciones de los demás... :D

Pero esta super. Yo mismo lo

Pero esta super. Yo mismo lo puse en dos sentencias antes de darme cuena de que se podía en 1 ( y eso que le estuve dando y dando vueltas )

Imagen de Jose_Gastelum

eso esta facil

hagan el ejercicio del web services de amazon jajjaa

Mi solución

Hola, bueno leyendo el reto un poco tarde pero ya encontré una solución, espero les agrade.

public static String replace( String in ){    
  String xs="";
  while(in.indexOf("l")>-1)
     in = in.substring(0,in.indexOf("l"))+(xs+="x")+in.substring(in.indexOf("l")+1);
  return in;
}

Espero sus comentarios.

Yeap!.. si te das cuenta un

Yeap!.. si te das cuenta un while es:

incializacion
while( condicion )
cuerpo / incremento

Puedes lograr lo mismo con un for por que tiene esas mismas tres partes, así que reescribiendolo podría quedar en un solo for.

for( String xs = ""; in.indexOf("1") > -1 ; in = in.substring( o, in.indexOf("l")) + ( xs += "x" ) + in.substring( in.indexOf("l") + 1 );  
return in;

O algo así. Está interesante no?

Imagen de rodrigo salado anaya

Mi solución groovy!! (1)

def replace(input){
    output = ''
    input.inject(1){ count, letter ->
       output += (letter == 'L'? 'x'* count++: letter)
       count
    }
    output
}

assert replace('HELLO WORLD')  == 'HExxxO WORxxxD'
assert replace('HELLO LAZY LIMBO WORLD') == 'HExxxO xxxAZY xxxxIMBO WORxxxxxD'

Imagen de rodrigo salado anaya

Mi solución groovy!! (2)

def replace(input){
    count = 1
    output = ''
    input.each{
        output += it == 'L'? 'x'* count++: it
    }
    output
}

assert replace('HELLO WORLD')  == 'HExxxO WORxxxD'
assert replace('HELLO LAZY LIMBO WORLD') == 'HExxxO xxxAZY xxxxIMBO WORxxxxxD'

@Rod me gusta más la

@Rod me gusta más la segunda. Pregunta: ¿Sientes que haber estado programando en C# te ha hecho mejor programador Groovy?

Imagen de rodrigo salado anaya

Linq (C#)

Creo que he mejorado como programador porque estuve mucho tiempo con muy buenos programadores; y aun sigo :P, pero también creo que usar Linq (C#) como locos TODO el tiempo... si cambio la manera en que veo Groovy : )

style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">