Foros del Web » Programando para Internet » PHP »

[Desafío PHP] Función reduce()

Estas en el tema de [Desafío PHP] Función reduce() en el foro de PHP en Foros del Web. Vallu @import url("http://static.forosdelweb.com/clientscript/vbulletin_css/geshi.css"); Código php: Ver original function reduce ( $text ) {     $arr_txt = str_split ( $text ) ;     $str ...

  #31 (permalink)  
Antiguo 10/07/2010, 15:36
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

Vallu
Código php:
Ver original
  1. function reduce($text){
  2.     $arr_txt = str_split($text);
  3.     $str='';
  4.     $creciente=false;
  5.     $max_creciente='';
  6.     $decreciente=false;
  7.     $max_decreciente='';
  8.     $max_length=count($arr_txt);
  9.     $contador_cre=0;
  10.     $contador_de=0;
  11. //recorro el array en el qual esta la cadena a compilar
  12.     for($i=0;$i<$max_length;$i++){
  13.         if($i==0){
  14.             $str=$arr_txt[$i];
  15.         }else{
  16.             if($arr_txt[$i]==$arr_txt[$i-1]){ //si la letra la siguente de la anterior
  17.                 if($creciente){
  18.                     if($contador_cre>1){ //y el contador dice que hay 2 o mas
  19.                         $str.="-".$max_creciente; //se acorta con la forma a-c
  20.                     }else{
  21.                         $str.=$max_creciente;
  22.                     }
  23.                     $contador_cre=0;
  24.                     $creciente=false;
  25.                 }elseif($decreciente){ //lo mismo pero en decreciente
  26.                     if($contador_de>1){
  27.                         $str.="-".$max_decreciente;
  28.                     }else{
  29.                         $str.=$max_decreciente;
  30.                     }
  31.                     $contador_de=0;
  32.                     $decreciente=false;
  33.                 }
  34.                 $str.=$arr_txt[$i];
  35.             }elseif((ord($arr_txt[$i])-1)==ord($arr_txt[$i-1])){ //La anterior letra es mas pequeña
  36.                 if($i==$max_length-1){ //Si es la ultima letra de la cadena
  37.                     if($contador_cre>0){ //y el contador no es 0
  38.                         $str.="-".$arr_txt[$i];
  39.                     }else{
  40.                         $str.=$arr_txt[$i-1].$arr_txt[$i];
  41.                     }
  42.                 }else{
  43.                     if($decreciente){ //si no es la ultima letra de la cadena
  44.                         if($contador_de>1){ //y venimos de una cadena decreciente
  45.                             $str.="-".$max_decreciente;
  46.                         }else{
  47.                             $str.=$max_decreciente;
  48.                         }
  49.                         $contador_de=0;
  50.                     }
  51.                     $contador_cre++;
  52.                     $creciente=true;
  53.                     $max_creciente=$arr_txt[$i];
  54.                     $decreciente=false;
  55.                     $max_decreciente='';
  56.                 }
  57.             }elseif((ord($arr_txt[$i])+1)==ord($arr_txt[$i-1])){ //La anterior letra es mas grande
  58.                 if($i==$max_length-1){ //Si es la ultima letra de la cadena
  59.                     if($contador_de>0){
  60.                         $str.="-".$arr_txt[$i];
  61.                     }else{
  62.                         $str.=$arr_txt[$i-1].$arr_txt[$i];
  63.                     }
  64.                 }else{ //si no es la utlima letra de la cadena
  65.                     if($creciente){
  66.                         if($contador_cre>1){
  67.                             $str.="-".$max_creciente;
  68.                         }else{
  69.                             $str.=$max_creciente;
  70.                         }
  71.                         $contador_cre=0;
  72.                     }
  73.                     $contador_de++;
  74.                     $decreciente=true;
  75.                     $max_decreciente=$arr_txt[$i];
  76.                     $creciente=false;
  77.                     $max_creciente='';
  78.                 }
  79.             }else{ //si la letra no viene de creciente o decreciente
  80.                 if($creciente){ //pero la anterior letra si es creciente
  81.                     if($contador_cre>1){
  82.                         $str.="-".$max_creciente;
  83.                     }else{
  84.                         $str.=$max_creciente;
  85.                     }
  86.                     $creciente=false;
  87.                     $contador_cre=0;
  88.                 }elseif($decreciente){ //mismo per en decreciente
  89.                     if($contador_de>1){
  90.                         $str.="-".$max_decreciente;
  91.                     }else{
  92.                         $str.=$max_decreciente;
  93.                     }
  94.                     $decreciente=false;
  95.                     $contador_de=0;
  96.                 }
  97.                 $str.=$arr_txt[$i];
  98.             }
  99.         }
  100.     }
  101.     return $str;
  102. }

Les presento el código mas largo de la competencia, como pueden ver resulta muy claro si se lee poco a poco. Personalmente lo veo complicado con mucho if-then-else, y realmente no lo entiendo del todo.

Sin embargo cabe destacar el uso de arreglos a partir de una cadena, una técnica que veremos a lo largo de las siguientes participaciones.
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #32 (permalink)  
Antiguo 10/07/2010, 15:42
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

santris
Código PHP:
Ver original
  1. function reduce($texto){
  2. $resultado = $nuevo_resultado = $sub_trozo = $trozo2 = $sub_trozo2 = '';
  3. //creamos la cadena contra la que realizaremos las comparaciones
  4. $cadena_comp="abcdefghijklmnopqrstuvwxyz";
  5. //asignamos la longitudud de la cadena $texto a la variable $longitud_cadena
  6. $longitud_cadena=strlen($texto);
  7. $nuevo_texto=$texto.substr($texto,-1);//arreglo
  8. //creamos un bucle en el cual el número de iteraciones es igual al valor de $longitud_cadena
  9. $i=0;
  10. for ($i=0; $i<=$longitud_cadena; $i++){
  11.     $sub_trozo.=substr($nuevo_texto,$i,1);
  12.     //comparamos al valor de la variable $sub_trozo con la cadena de comparación $cadena_comp, si es cierto asignamos el valor de $sub_trozo a la variable $trozo
  13.     if(preg_match("/$sub_trozo/",$cadena_comp))
  14.         $trozo=$sub_trozo;
  15.     //en caso contrario evaluamos las variables $trozo y sub_trozo
  16.     else{
  17.         if(strlen($trozo)>0){
  18.             if(strlen($trozo)>2){
  19.                 $str_reducido=substr($trozo,0,1)."-".substr($trozo,-1);
  20.                 $resultado.=$str_reducido;
  21.             }
  22.             else
  23.                 $resultado.=$trozo;
  24.         $sub_trozo = '';//vaciamos
  25.         $trozo = '';//vaciamos
  26.         $i=$i-1;//descontamos un incremento por la letra que ocasionó la comparación negativa
  27.         }
  28.         else{
  29.             if(strlen($sub_trozo)>2){
  30.                 $str_reducido=substr($sub_trozo,0,1)."-".substr($sub_trozo,-1);
  31.                 $resultado.=$str_reducido;
  32.             }
  33.             else
  34.                 $resultado.=$sub_trozo;
  35.         $sub_trozo = '';
  36.         $trozo = '';
  37.         $i=$i-1;
  38.         }
  39.     }
  40. }
  41. //invertimos la cadena de comparación y realizamos el mismo procedimiento anterior
  42. $nueva_cadena_comp=strrev($cadena_comp);
  43. $longitud_cadena2=strlen($resultado);
  44. $nuevo_texto2=$resultado.substr($resultado,-1);
  45. $i=0;
  46. for ($i=0; $i<=$longitud_cadena2; $i++){
  47.     $sub_trozo2.=substr($nuevo_texto2,$i,1);
  48.     if(preg_match("/$sub_trozo2/",$nueva_cadena_comp))
  49.         $trozo2=$sub_trozo2;
  50.     else{
  51.         if(strlen($trozo2)>0){
  52.             if(strlen($trozo2)>2){
  53.                 $str_reducido2=substr($trozo2,0,1)."-".substr($trozo2,-1);
  54.                 $nuevo_resultado.=$str_reducido2;
  55.             }
  56.             else
  57.                 $nuevo_resultado.=$trozo2;
  58.         if($trozo2!="-")
  59.             $i=$i-1;
  60.         $sub_trozo2 ='';
  61.         $trozo2 = '';
  62.         }
  63.         else{
  64.             if(strlen($sub_trozo2)>2){
  65.                 $str_reducido2=substr($sub_trozo2,0,1)."-".substr($sub_trozo2,-1);
  66.                 $nuevo_resultado.=$str_reducido2;
  67.             }
  68.             else
  69.                 $nuevo_resultado.=$sub_trozo2;
  70.         if($sub_trozo2!="-")
  71.             $i=$i-1;
  72.         $sub_trozo2 = '';
  73.         $trozo2 = '';
  74.         }
  75.     }
  76. }
  77. return $nuevo_resultado;
  78. }

Siguiendo el sendero de los scripts largos les presento este código. Aquí, lo curioso es el uso de cadenas auxiliares para comprobar la pertenencia del conjunto a-z

También debo mencionar un detalle que me encontré en la etapa de evaluación: el uso de unset(), en algunas secuencias de código hacía uso de unset($foo); en lugar de solo $foo='';

El problema radicaba en que a la siguiente vuelta del bucle, si antes fue unseteada alguna variable esta ya no existe -realmente- en el contexto, además del proceso de concatenación por variables indefinidas, etc...

Es un buen trabajo no lo dudo, y da los resultados esperados. Un ejemplo interesante es la reversa que aplica en el código, para el análisis contrario de secuencias z-a. La implementación dejó varia cháchara de que hablar, muchas gracias...
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #33 (permalink)  
Antiguo 10/07/2010, 15:49
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

Triby
Código PHP:
Ver original
  1. function reduce ($str) {
  2.     // Patrón para comparación
  3.     $letters = 'abcdefghijklmnopqrstuvwxyz';
  4.     // Dirección actual
  5.     $dir = 'no';
  6.     // Longitud  de la cadena original
  7.     $strlen = strlen($str) - 1;
  8.      // Primer caracter directo
  9.     $reduce = $str[0];
  10.     // Iniciamos desde el segundo
  11.     for ($i = 1; $i <= $strlen; $i++):
  12.         // Caracter actual y su posición en el patrón
  13.         $char = $str[$i];
  14.         $pos = strpos($letters, $char);
  15.         // Caracter anterior en $str y su posición
  16.         $lastchar = $str[$i - 1];
  17.         $lastpos = strpos($letters, $lastchar);
  18.  
  19.         // Secuencia y dirección?
  20.         if ($pos == ($lastpos + 1)  && ($dir == 'left' || $dir == 'no')):
  21.             // Secuencia izq
  22.             $dir = 'left';
  23.             if ($i < $strlen):
  24.                 // Si no es el último caracter
  25.                 continue;
  26.             endif;
  27.         elseif ($pos == ($lastpos - 1) && ($dir == 'right' || $dir == 'no')):
  28.             // Secuencia der
  29.             $dir = 'right';
  30.             if ($i < $strlen):
  31.                 // Si no es el último caracter
  32.                 continue;
  33.             endif;
  34.         elseif ($dir == 'no'):
  35.             // No hay secuencia
  36.             $reduce .= $char;
  37.             continue;
  38.         endif;
  39.         // Por default
  40.         $reverse = false;
  41.         // Cambio de sentido?
  42.         if ($i < $strlen):
  43.             // Siguiente caracter y posición para verificar
  44.             $newchar = $str[$i + 1];
  45.             $newpos = strpos($letters, $newchar);
  46.             // Cambio de dirección?
  47.             $reverse = (($dir == 'left' && $pos == ($newpos + 1) && $lastpos == ($newpos + 2))
  48.                 || ($dir == 'right' && $pos == ($newpos - 1) && $lastpos == ($newpos - 2)));
  49.             if ($reverse):
  50.                 // Aplicamos la nueva dirección
  51.                 $dir = ($pos == ($newpos - 1)) ? 'left' : 'right';
  52.             else:
  53.                 // Cancelamos dirección anterior
  54.                 $dir = 'no';
  55.             endif;
  56.         else:
  57.             $dir = 'no';
  58.         endif;
  59.         // Fin de secuencia y/o cambio de dirección
  60.  
  61.         // Posición del último caracter de $reduce
  62.         $redpos = strpos($letters, $reduce[strlen($reduce) - 1]);
  63.         // Verificamos cantidad caracteres
  64.         $abs = abs($redpos - $lastpos);
  65.  
  66.         // Último caracter de $str
  67.         if ($i == $strlen):
  68.             if ($abs == 0):
  69.                 // No hay secuencia
  70.                 $reduce .= $char;
  71.             elseif (abs($pos - $lastpos) != 1):
  72.                 // No hay secuencia, quedaba pendiente caracter anterior
  73.                 $reduce .= "-{$lastchar}{$char}";
  74.             else:
  75.                 // Sí hay secuencia
  76.                 $reduce .= "-{$char}";
  77.             endif;
  78.         elseif ($abs > 1):
  79.             // Secuencia más de 2 caracteres
  80.             // ? - Cambio, omite el caracter actual
  81.             // : - No cambio, se agregan guión, último y caracter actual
  82.             $reduce .= ($reverse) ? "-{$lastchar}" : "-{$lastchar}{$char}";
  83.         else:
  84.             // Secuencia es de sólo dos caracteres   ab
  85.             // ? - Cambio, se omite el caracter actual
  86.             // : - No cambio, se agregan último y caracter actual
  87.             $reduce .= ($reverse) ? $lastchar : "{$lastchar}{$char}";
  88.         endif;
  89.     endfor;
  90.     return $reduce;
  91. }

Otro script que usa cadenas auxiliares para comprobar el rango, y que tampoco entiendo del todo.

Cabe mencionar que realmente es complicado traducir un algoritmo mental en código claro, esto es cierto también pero comprender el proceso inverso es realmente complicado, sino hasta difícil. (:

Es interesante la sintaxis que se utiliza en este script, desde versiones alternativas de keywords para control de flujo, aka. endif, endfor, etc.. así como también un uso correcto y casi magistral de variables, comparaciones, comillas y comentarios.
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #34 (permalink)  
Antiguo 10/07/2010, 15:54
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

gary_qwerty
Código PHP:
Ver original
  1. function reduce($string){
  2.  
  3.     if( strlen($string) < 3 ){
  4.         return $string;
  5.     }
  6.  
  7.     $abc = array("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z");
  8.  
  9.     $str_arr = array();
  10.     $c = 0;
  11.     while( $c < strlen($string) ){
  12.         $str_arr[] = substr($string, $c, 1);
  13.         $c++;
  14.     }
  15.  
  16.     $str_replace = $str_arr;
  17.     foreach($str_arr as $k=>$letter){
  18.         $val = array_search($letter, $abc);
  19.         if( isset( $str_arr[$k+1] ) ){
  20.             if( isset($abc[$val+1]) && $str_arr[$k+1] ==  $abc[$val+1] ){
  21.                 if( isset($str_arr[$k+2])  && isset($abc[$val+2]) && $str_arr[$k+2] == $abc[$val+2] ){
  22.                     unset($str_replace[$k+1]);
  23.                 }
  24.             }
  25.             else if( isset($abc[$val-1]) && $str_arr[$k+1] ==  $abc[$val-1] ){
  26.                 if( isset($str_arr[$k+2]) && isset($abc[$val-2]) &&  $str_arr[$k+2] == $abc[$val-2]  ){
  27.                     unset($str_replace[$k+1]);
  28.                 }
  29.             }
  30.         }
  31.     }
  32.  
  33.     $keys = array();
  34.     $letters = array();
  35.     foreach($str_replace as $k=>$l){
  36.         $keys[] = $k;
  37.         $letters[] = $l;
  38.     }
  39.  
  40.     $ret = "";
  41.  
  42.     foreach($keys as $k=>$l){
  43.         if( isset($keys[$k+1]) ){
  44.             if( $l+1 == $keys[$k+1] ){
  45.                 $ret .= $letters[$k];
  46.             }
  47.             else{
  48.                 $ret .= $letters[$k]."-";
  49.             }
  50.         }
  51.         else{
  52.             $ret .= $letters[$k]."-";
  53.         }
  54.     }
  55.  
  56.     $ret = substr($ret, 0, strlen($ret)-1 );
  57.     return $ret;
  58. }

Un script de mas de 1000B, y que siendo aún mas corto que otros no es mas veloz.

Haciendo una bella combinación de cadenas, arreglos y bucles consigue pasar las pruebas y aquí lo tenemos. Según se cuenta, una simple corrección y ya tenemos listo todo el algoritmo.

Sin duda códigos como esto demuestra la flexibilidad no del lenguaje, sino de la mente humana. ;)
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #35 (permalink)  
Antiguo 10/07/2010, 15:57
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

oso96_2000
Código PHP:
Ver original
  1. function reduce ($text = null) {
  2.     // Revisamos que exista un texto y que sean caracteres permitidos
  3.     if (empty($text) || (bool) preg_match('/[^a-z]+/', $text)) {
  4.         trigger_error('Debes especificar una cadena consistente en caracteres de la "a" a la "z". Cadena enviada: ' . $text, E_USER_ERROR);
  5.     }
  6.  
  7.     // Creamos un arreglo a partir del texto
  8.     $characters = function_exists('str_split') ? str_split($text) : preg_split('@([a-z]{1})@', $text, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY) ;
  9.  
  10.     // Declaramos variables
  11.     $total  = count($characters);
  12.     $result = '';
  13.     $now    = '';
  14.     $prev   = false;
  15.     $next   = false;
  16.  
  17.     //Comenzamos el loop
  18.     for ($i = 0; $i < $total; $i++) {
  19.         // Obtenemos el caracter siguiente
  20.         $next   = isset($characters[$i + 1]) ? $characters[$i + 1] : false ;
  21.  
  22.         //
  23.         if ($characters[$i] == $next || $characters[$i] == $prev) {
  24.             $now = $characters[$i];
  25.         }else{
  26.             $now = '-';
  27.         }
  28.  
  29.         // Si estamos en medio de una secuencia y hay que romperla
  30.         if ($now == '-' && (ord($characters[$i]) + 1 != ord($next) || ord($characters[$i]) - 1 != ord($prev))) {
  31.             $now = $characters[$i];
  32.         }
  33.  
  34.         // Secuencia de reversa
  35.         if (ord($characters[$i]) + 1 == ord($prev) && ord($characters[$i]) - 1 == ord($next)) {
  36.             $now = '-';
  37.         }
  38.  
  39.         // Si es el primero o ultimo
  40.         if ($i == 0 || $i == ($total - 1)) {
  41.             $now = $characters[$i];
  42.         }
  43.  
  44.         // Asignamos el caracter actual
  45.         $result .= $now;
  46.  
  47.         // Guardamos para saber cual era el caracter anterior
  48.         $prev   = $characters[$i];
  49.     }
  50.  
  51.     // Quitamos guiones innecesarios
  52.     $result = preg_replace('/-{2,}/', '-', $result);
  53.     $result = trim($result, '- ');
  54.  
  55.     return $result;
  56. }

Y de ultimo momento nos llegó este otro código para la competición. Sin duda un código claro y controlado, que sin embargo no consigue superar a la mayoría de otros códigos cual fideos parecieran.

Me gusto el uso de un solo bucle e if-then-else especifico y breve.
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #36 (permalink)  
Antiguo 10/07/2010, 16:02
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

De_la_Cuesta_13
Código PHP:
Ver original
  1. function reduce($str){
  2.  
  3.     $str = strtolower($str);
  4.     $abc = "abcdefghijklmnopqrstuvwxyz";
  5.  
  6.     $a = str_split($abc);
  7.     $s = str_split($str);
  8.     $l_str = strlen($str);
  9.     $ult_str = $l_str - 1;
  10.     $ult_abc = strlen($abc) - 1;
  11.     $salida = "";
  12.     $m = 0;
  13.     $t = 0;
  14.  
  15.     for($i=0;$i<$l_str;$i++){
  16.  
  17.         if($m==1)
  18.             $i--;
  19.  
  20.         /*
  21.             $j me indica en que posición del abecedario ($abc) se encuentra el caracter actual ($i), así:
  22.             1. Si el caracter que sigue en $abc ($j+1) es igual al que sigue en $str ($i+1), se busca reducir en orden.
  23.             2. Si el caracter anterior en $abc ($j-1) es igual al que sigue en $str ($i+1), se busca reducir en reversa.
  24.         */
  25.         $j = strpos($abc, $str{$i});
  26.  
  27.         //busco en orden
  28.         if($i<$ult_str && $j<$ult_abc && $abc{$j+1}==$str{$i+1}){
  29.             if($m==1)
  30.                 $m=0;
  31.             else
  32.                 $salida .= $str{$i};
  33.             $j++;
  34.             $k = $i;
  35.             $i++;
  36.             //busco hasta que posición $str es igual a $abc, en orden
  37.             for($p=$i;$p<$l_str;$p++){
  38.                 if($j<=$ult_abc && $a[$j]==$s[$p]){
  39.                     $j++;
  40.                     continue;
  41.                 }
  42.                 else
  43.                     break;
  44.             }
  45.  
  46.             $p--;
  47.             $i = $p;
  48.             // se debe reducir porque hay 3 o más caracteres en orden
  49.             if(($i-$k)>=2)
  50.                 $salida .= "-".$str{$i};
  51.             else
  52.                 $salida .= $str{$i};
  53.             /*
  54.                 reviso si después del último caracter en order se debe reducir en reversa.
  55.                 $t = 1, sí
  56.                 NOTA: Si $t = 1, no se agrega el caracter a la salida en la posición $i, puesto
  57.                 que ya se ha agregado en orden.
  58.             */
  59.             $t=1;
  60.         }
  61.  
  62.         if($t==1)
  63.             $j = strpos($abc, $str{$i});
  64.  
  65.         //busco en reversa
  66.         if($i<$ult_str && $j>0 && $a{$j-1}==$str{$i+1}){
  67.             if($t!=1)
  68.                 $salida .= $str{$i};
  69.             $j--;
  70.             $k = $i;
  71.             $i++;
  72.             //busco hasta que posición $str es igual a $abc, en reversa
  73.             for($p=$i;$p<$l_str;$p++){
  74.                 if($j>=0 && $a[$j]==$s[$p]){
  75.                     $j--;
  76.                     continue;
  77.                 }
  78.                 else
  79.                     break;
  80.             }
  81.  
  82.             $p--;
  83.             $i = $p;
  84.             // se debe reducir porque hay 3 o más caracteres en reversa
  85.             if(($i-$k)>=2)
  86.                 $salida .= "-".$str{$i};
  87.             else
  88.                 $salida .= $str{$i};
  89.             /*
  90.                 reviso si después del último caracter en reversa se debe reducir en orden.
  91.                 $m = 1, sí
  92.                 NOTA: Si $m = 1, no se agrega el siguiente caracter en la posición $i, puesto
  93.                 que ya se ha agregado en reversa.
  94.             */
  95.             $j = strpos($abc, $str{$i});
  96.             if($i<$ult_str && $abc{$j+1}==$str{$i+1})
  97.                 $m=1;
  98.         }
  99.  
  100.         else{
  101.             if($t!=1)
  102.                 $salida .= $str{$i};
  103.         }
  104.         $t=0;
  105.     }
  106.  
  107.     return $salida;
  108. }

Esta es la viva imagen de que un código largo no necesariamente es lento, sino todo lo contrario.

El código ganador en velocidad bajo las pruebas actuales, el mas rápido, si... sin duda. Que al igual que otros scripts usa cadenas, arreglos auxiliares, y casi imposible de creer mas de un solo bucle.

Excelente.
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #37 (permalink)  
Antiguo 11/07/2010, 11:22
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

Definitivamente los códigos largos son impactantes, y hasta entendibles... ¿pero que sucede con los códigos menores a 1000B?

¿serán igual de claros? ¿precisos? ¿rápidos?

Pues precisamente no mas rápidos... en la mayoría de los casos nada claros, pero el ingenio hace reducir incluso nuestras participaciones, llegando a un niveles tan abstractos que si valen la pena divulgar!!

Ya teniendo un código más rápido, y a sabiendas de a quien le pertenece el mas corto continuemos con la pasarela de mini-faldas.... (;

__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #38 (permalink)  
Antiguo 11/07/2010, 11:50
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

GatorV
Código PHP:
Ver original
  1. function reduce($cadena)
  2. {
  3.     if (strlen($cadena) < 3) {
  4.         return $cadena;
  5.     }
  6.  
  7.     $chars = preg_split('//', $cadena, -1, PREG_SPLIT_NO_EMPTY);
  8.     $size = count($chars);
  9.     $out = array();
  10.     $pos = 0;
  11.  
  12.     while($pos < $size) {
  13.         $current = ord($chars[$pos]);
  14.         $next = (isset($chars[($pos + 1)])) ? ord($chars[($pos + 1)]) : 0;
  15.         $onext = (isset($chars[($pos + 2)])) ? ord($chars[($pos + 2)]) : 0;
  16.         $out[] = $chars[$pos];
  17.  
  18.         if (($current + 1) == $next && (($current + 2) == $onext)) {
  19.             $out[] = '-';
  20.             do {
  21.                 $pos++;
  22.                 $current = ord($chars[$pos]);
  23.                 $next = (isset($chars[($pos + 1)])) ? ord($chars[($pos + 1)]) : 0;
  24.                 if (($current + 1) != $next) {
  25.                     break;
  26.                 }
  27.             } while(true);
  28.         } elseif ((($current - 1) == $next) && (($current - 2) == $onext)) {
  29.             $out[] = '-';
  30.             do {
  31.                 $pos++;
  32.                 $current = ord($chars[$pos]);
  33.                 $next = (isset($chars[($pos + 1)])) ? ord($chars[($pos + 1)]) : false;
  34.                 if (($current - 1) != $next) {
  35.                     break;
  36.                 }
  37.             } while(true);
  38.         } else {
  39.             $pos++;
  40.         }
  41.     }
  42.  
  43.     return implode('', $out);
  44. }
He aquí el primer código de un moderador del foro de PHP, que como pueden observar hace un serie de elegantes bucles, muy interesante y sin comentarios. Pero es entendible, y bien, no es lo mas corto... pero que bueno se pone esto!!

La comparación lógica de los números ordinales en la secuencia de caracteres es solo una parte del problema, que como pocos supo resolver de manera efectiva y breve. Además coloca su código dentro de los mas rápidos cerca de la media 0.0050
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #39 (permalink)  
Antiguo 11/07/2010, 11:57
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

pateketrueke
Código PHP:
Ver original
  1. function reduce($text)
  2. {
  3.     $key = 0;
  4.     $str = array();
  5.  
  6.     $test = addcslashes($text, $text);
  7.     $array = explode('\\', trim($test, '\\'));
  8.  
  9.     do
  10.     {
  11.         if (empty($str))
  12.         {
  13.             if (strlen($text) < 3) return $text;
  14.             $str []= $array[$key++];
  15.             continue;
  16.         }
  17.         elseif ( ! isset($array[$key]))
  18.         {
  19.             if (end($str) != $current) $str []= $current;
  20.             return join('', $str);
  21.         }
  22.  
  23.         $left = ord($prev = $array[$key -1]);
  24.         $right = ord($current = $array[$key++]);
  25.  
  26.         if (($factor = abs($left - $right)) == 0 OR $factor > 1)
  27.         {
  28.             if (end($str) == '-') $str []= $prev;
  29.             $str []= $current;
  30.         }
  31.         elseif ($factor == 1)
  32.         {
  33.             $next = isset($array[$key])? $array[$key]: '';
  34.             switch (1)
  35.             {
  36.                 default: break;
  37.                 case ($left < $right && $right > ord($next));
  38.                 case ($left > $right && $right < ord($next));
  39.                     $str []= $current;
  40.                 break;
  41.                 case (end($str) != '-');
  42.                     if (abs(ord($next) - $right) != 1) $str []= $current;
  43.                     else $str []= '-';
  44.                 break;
  45.             }
  46.  
  47.         }
  48.     } while (1);
  49. }

Yo. Igualmente sin comentarios, que les puedo decir: me gustan muchos los arreglos, y sabiendo que muchos usarían algún método split quise hacer algo distinto. Me agrada usar bucles lógicos, condicionales y asignaciones extrañas, etc.

Eso lo digo yo, porque nadie puede juzgar mi código mas que el jurado electo para el reto.

Por debajo de la mayoría, mi participación no resultó la mas veloz, mucho menos más la mas corta... pero que entretenido fue escribir la trivial función.
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #40 (permalink)  
Antiguo 11/07/2010, 12:04
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

abimaelrc
Código PHP:
Ver original
  1. function reduce($text)
  2. {
  3. /*
  4.     Variables
  5.  
  6.     $lastChar = número ascii de caracter anterior
  7.     $chars = array temporal que contiene los caracteres posibles a reducir
  8.     $n = número de la llave de la variable $chars
  9.     $tries = número para verificar si es mayor a 3 reducir caracteres
  10.             indicados en la variable chars
  11.     $boolPos = boolean para caracteres que van aumentando
  12.     $boolNeg = boolean para caracteres que van disminuyendo
  13. */
  14.     $lastChar = 1;
  15.     $chars = array();
  16.     $n = 0;
  17.     $tries = 1;
  18.     $boolPos = false;
  19.     $boolNeg = false;
  20.  
  21.     for($i=0; $i<strlen($text); $i++){
  22.         // Obtener el valor ASCII
  23.         $asciiVal = ord($text[$i]);
  24.  
  25.         /*
  26.         Verifica si el valor ASCII corriente es menor al valor ASCII del caracter
  27.         anterior (caracteres de mayor a menor) y si es consecutivo. Si se cumple
  28.         entonces verifica si se había ejecutado anteriormente la segunda condición
  29.         para resetear la variable $tries o continuarla. Si la variable $tries es
  30.         mayor o igual a tres, coloca el guión sino lo contrario y se añade el
  31.         caracter corriente. La variable $chars se sobre-escribe cuando hay más
  32.         de tres caracteres consecutivos. Se verifica si el próximo caracter existe
  33.         y si cambia el proceso (es decir verifica si cambia de mayor -> menor,
  34.         a menor -> mayor el caracter) para aumentar la variable $n y añadir el
  35.         siguiente caracter en un nuevo espacio en la variable $chars. Se
  36.         modifican los valores booleanos para el siguiente caracter.
  37.         */
  38.         if($asciiVal < $lastChar && ($lastChar % $asciiVal) == 1){
  39.             $tries = $boolPos ? 2 : ++$tries;
  40.             $chars[$n] = ($tries >= 3 ? '-' : '') . $text[$i];
  41.             if(!empty($text[$i + 1]) && ord($text[$i + 1]) > $asciiVal){
  42.                 ++$n;
  43.             }
  44.             $boolNeg = true;
  45.             $boolPos = false;
  46.         }
  47.  
  48.         /*
  49.         Es el mismo proceso de la condición anterior pero de menor a mayor
  50.         los caracteres.
  51.         */
  52.         elseif($asciiVal > $lastChar && ($asciiVal % $lastChar) == 1){
  53.             $tries = $boolNeg ? 2 : ++$tries;
  54.             $chars[$n] = ($tries >= 3 ? '-' : '') . $text[$i];
  55.             if(!empty($text[$i + 1]) && ord($text[$i + 1]) < $asciiVal){
  56.                 ++$n;
  57.             }
  58.             $boolPos = true;
  59.             $boolNeg = false;
  60.         }
  61.  
  62.         // Es para los resultados que no son consecutivos y el primer caracter.
  63.         else{
  64.             $chars[$n] = (!empty($chars[$n]) ? $chars[$n] : '') . $text[$i];
  65.             ++$n;
  66.             $tries = 1;
  67.         }
  68.  
  69.         // Almacenar el caracter corriente para usarlo en la siguiente vuelta
  70.         $lastChar = $asciiVal;
  71.     }
  72.  
  73.     // Retornar el valor y unir los caracteres almacenados en la variable $chars
  74.     return implode('',$chars);
  75. }

Es un código corto, los comentarios no se cuenta lo aseguro. Esta es la primera participación en la que me encuentro una comparación con módulos.

Bastante claro y muy bien expresado, felicitaciones!!
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #41 (permalink)  
Antiguo 11/07/2010, 12:09
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

maycolalvarez
Código PHP:
Ver original
  1. function reduce($str)
  2.  {
  3.      $charSequence       = null; // contiene el carácter que inicia una  secuencia:
  4.      $charSequenceDiff   = 0;    // contiene la diferencia con la cual se  identifica la secuencia (+1 ó -1)
  5.      $result             = '';   // cadena donde se vuelcan los  resultados
  6.  
  7.      for ($i = 0; $i < strlen($str); $i++) {
  8.          // extrae el carácter actual y el proximo:
  9.          $current        = $str[$i];
  10.          $next           = isset($str[$i + 1]) ? $str[$i + 1] : null;
  11.          // obtiene su valor ASCII para comparar:
  12.          $currentChar    = ord($current);
  13.          $nextChar       = ord($next);
  14.          // obtiene el valor absoluto para determinar si están en  secuencia
  15.          $absoluteDiff   = abs($currentChar - $nextChar);
  16.  
  17.          if (($absoluteDiff == 0) || ($absoluteDiff > 1)) {
  18.              if (($charSequence != null) &&  (abs(ord($charSequence) - $currentChar) > 1)) {
  19.                  $result .= '-';
  20.              }
  21.              $result.= $current;
  22.              $charSequence   =  null;
  23.          } else {
  24.              // diferencia entre los caracteres consecutivos (-1  incremento, +1 decremento)
  25.              $diff = ($currentChar - $nextChar);
  26.  
  27.              if(($charSequence == null) || ($charSequenceDiff != $diff)) {
  28.                  if(($charSequence != null) &&  (abs(ord($charSequence) - $currentChar) > 1)) {
  29.                      $result .= '-';
  30.                  }
  31.                  $result.= $current;
  32.                  $charSequence       = $current;
  33.                  $charSequenceDiff   = $diff;
  34.              }
  35.          }
  36.      }
  37.      return $result;
  38.  }

Si bien recuerdo, este fue el primer código que recibí.

El comparar un valor absoluto en cuanto a la diferencia en la secuencia a-z es crucial, al momento de implementar la comparación normal e invertida. Si, ya se que no se entiende lo que digo... pero juro que otra clave se encuentra ahí.
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #42 (permalink)  
Antiguo 11/07/2010, 12:15
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

Gustavo72
Código PHP:
Ver original
  1. function reduce($text) {
  2.     //La función recorre la cadena comparando cada caracter con el anterior.
  3.     //Los caracteres solo se agregan al resultado final si no hay secuencia.
  4.     //Cuando una secuencia termina se agrega el caracter anterior al resultado; si la secuencia es de más de dos letras se agrega antes un guión.
  5.     $res=""; //En esta cadena construyo el resultado.
  6.     $carAnt=""; //Esta variable guardará el caracter anterior.
  7.     $codAnt=0; //Esta variable guardará el código ASCII del caracter anterior.
  8.     $secuencia=0; //Esta variable contará la cantidad de caracteres en secuencia menos 1. Su signo indicará el sentido ascendente (+) o descendente (-).
  9.     $text.=" ";
  10.     for ($a=0; $a<strlen($text); $a++) { //Recorro la cadena:
  11.         $sinSecuencia=true;
  12.         $nuevaSecuencia=0;
  13.         if (ord($text[$a])==$codAnt+1) { //Compara caracter con el anterior y detecta secuencia ascendente:
  14.             if ($secuencia<0)
  15.                 $nuevaSecuencia=1; //Se inicia secuencia ascendente en sentido contrario al actual
  16.             else {
  17.                 $secuencia++;
  18.                 $sinSecuencia=false;
  19.             }
  20.         }
  21.         elseif (ord($text[$a])==$codAnt-1) { //Compara caracter con el anterior y detecta secuencia descendente:
  22.             if ($secuencia>0)
  23.                 $nuevaSecuencia=-1; //Se inicia secuencia descendente en sentido contrario al actual
  24.             else {
  25.                 $secuencia--;
  26.                 $sinSecuencia=false;
  27.             }
  28.         }
  29.  
  30.         if ($sinSecuencia) { //No hay secuencia o se inició una en sentido opuesto:
  31.             if (abs($secuencia)==1)
  32.                 $res.=$carAnt; //Secuencia rota de solo dos letras. Agrego caracter anterior sin guión
  33.             elseif (abs($secuencia)>1)
  34.                 $res.="-$carAnt"; // Cierro secuencia de más de dos letras con guión y caracter anterior
  35.  
  36.             if (!$nuevaSecuencia) { //No se inicio nueva secuencia:
  37.                 $res.=$text[$a]; //Agrega el aactual
  38.                 $secuencia=0; //No secuencia
  39.             }
  40.             else
  41.                 $secuencia=$nuevaSecuencia; //Seteo secuencia en sentido contrario
  42.         }
  43.         $carAnt=$text[$a];
  44.         $codAnt=ord($text[$a]);
  45.     }
  46.     return trim($res);
  47. }

Otro lindo y corto script.

A diferencia de otras implementaciones, este código no hace uso de comparaciones con el siguiente carácter, o el siguiente del siguiente, etc..

Sabiendo la lógica impuesta, el uso razonable tan solo del carácter anterior de la secuencia actual es importante. Así, de una buena ves se evitan errores de undefined offset, etc..
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #43 (permalink)  
Antiguo 11/07/2010, 12:19
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

eZakto
Código PHP:
Ver original
  1. function reduce($string)
  2. {
  3.     // Compruebo que es posible que haya al menos un rango de 3 caracteres
  4.     if(strlen($string) < 3)
  5.     {
  6.         return $string;
  7.     }
  8.  
  9.     // Lista de carácteres permitidos
  10.     $charset = array_flip(array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'));
  11.  
  12.     // Guarda los cambios que se realicen
  13.     $cache   = $string;
  14.  
  15.     // Indica si la posición actual es dentro de un rango (false) o no (true)
  16.     $start   = true;
  17.  
  18.     // $position es la posición actual dentro de la cadena,
  19.     // $i = -1 hará que se parseen los rangos en orden alfabético, $i = 1 hará que sea al revés
  20.     for ($position = 1, $i = -1; $i < 2; ++$position)
  21.     {
  22.         // Almacena el último carácter tras la posición actual
  23.         $last = $string[$position-1];
  24.  
  25.         // Verifico en $charset si $last está inmediatamente antes/después que el carácter actual
  26.         // En caso contrario, en la próxima iteración comenzará a buscar un nuevo rango
  27.         if ($charset[$last] == ($charset[$string[$position]]+$i))
  28.         {
  29.             if ($start == true)
  30.             {
  31.                 // Estoy dentro de un rango
  32.                 $start = false;
  33.             }
  34.             else
  35.             {
  36.                 // Reemplazo el carácter anterior en $cache
  37.                 $cache[$position-1] = '-';
  38.             }
  39.         }
  40.         else
  41.         {
  42.             $start = true;
  43.         }
  44.  
  45.         // Una vez completado el recorrido de la cadena, reestabilizo $string, $position e $i
  46.         // para comenzar el recorrido nuevamente, pero parseando los rangos en orden inverso
  47.         if ($position >= strlen($string)-1)
  48.         {
  49.             $position = 0;
  50.             $i        = $i + 2;
  51.         }
  52.     }
  53.  
  54.     // Finalmente reemplazo los '-----' por '-'
  55.     return preg_replace('/-+/', '-', $cache);
  56. }

Con un bucle un tanto extraño, y también haciendo uso de arreglos auxiliares tenemos este otro script.

Omitiendo comentarios se nota que es realmente reducido, y bueno... la implementación si es de las mas atrevidas, un tanto por su bizarres y otro tanto por su precisión, quedando igualmente cerca de la media en tiempo de ejecución.
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #44 (permalink)  
Antiguo 11/07/2010, 12:22
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

AlvaroG
Código PHP:
Ver original
  1. function reduce($cadena) {
  2.     $continuar = true;
  3.     $pos = 0;
  4.     $nueva = "";
  5.     $max_pos = strlen($cadena)-1;
  6.  
  7.     // si la cadena es vacía o de largo 1, no continuar
  8.     if ($max_pos < 1) {
  9.         return $cadena;
  10.     }
  11.  
  12.     while ($continuar) {
  13.         // agrego a $nueva el caracter actual
  14.         $nueva .= $cadena{$pos};
  15.         $diferencia = ord($cadena{$pos}) - ord($cadena{$pos+1});
  16.  
  17.         // con esto se determina si el intervalo es creciente o decreciente (abc o cba)
  18.         if (abs($diferencia) == 1 ) {
  19.             $signo_diferencia = ($diferencia > 0) ? 1 : -1;
  20.  
  21.             $i = 2;
  22.             // busco el último caracter del intervalo
  23.             while( ($pos+$i <= $max_pos) && ((ord($cadena{$pos}) - ord($cadena{$pos+$i})) == $signo_diferencia*$i) ) {
  24.                 $i++;
  25.             }
  26.             // si el intervalo es de más de 2 caracteres (abc en vez de ab), agrego el - para separar
  27.             if ($i > 2) {
  28.                 $nueva .= '-';
  29.             }
  30.             // para la vuelta siguiente, empiezo a buscar un intervalo después del que acabo de encontrar
  31.             $pos += $i-1;
  32.  
  33.         } else {
  34.             $pos++;
  35.         }
  36.  
  37.         // si no llegué al final de $cadena, seguir recorriéndola
  38.         $continuar = ($pos < $max_pos);
  39.     }
  40.     // el último caracter de la cadena nunca es procesado por el while anterior. Devolver entonces lo que había
  41.     // juntado en $nueva + el último caracter
  42.     return $nueva.$cadena{$max_pos};
  43. }

Un código con dos bucles, y también dos diferencias notables.

Al menos, el problema nos indicaba un parte de la solución... el primer y último carácter permanecen intactos, además de que me fascinan los bucles lógicos.

¿ya se los había dicho?
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #45 (permalink)  
Antiguo 11/07/2010, 15:14
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

Para finalizar esta parte de la competencia solo falta mostrar ĺos tres códigos mas cortos, que no quiere decir rápidos por supuesto...

La elegancia de los códigos cortos me atrae mucho, y siendo scripter de antaño me recuerda el gran trabajo que suele haber detrás de un código pequeño, la mente de susodichos creadores es algo que me resulta perturbador si me dejan opinar algo...

Antes de, quiero agradecer de nuevo su participación y deseo con gran afán participar en algún otro reto que se proponga la comunidad. Gracias!!
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #46 (permalink)  
Antiguo 11/07/2010, 15:20
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

fran86
Código PHP:
Ver original
  1. function reduce($cadena)
  2. {
  3.     // Solo aplica a cadenas de 3 o mas caracteres
  4.     if (strlen($cadena) >= 3) {
  5.         // Agrega el extremo izquierdo
  6.         $cadenaReducida = $cadena[0];
  7.         // Recorre la cadena omitiendo el primer y ultimo caracter
  8.         for ($i=1; $i<strlen($cadena)-1; $i++) {
  9.             $iInicial = $i;
  10.             // Avanza la posicion del caracter si es el medio de un rango
  11.             while (   ($i+1 < strlen($cadena))
  12.                    && ($cadena[$i-1] != $cadena[$i+1])
  13.                    && ((ord($cadena[$i-1])+ord($cadena[$i+1]))/2 == ord($cadena[$i]))
  14.             ) {
  15.                 $i++;
  16.             }
  17.             // Agrega en $cadenaReducida de acuerdo a si se omitieron o no caracteres
  18.             if ($iInicial != $i) {
  19.                 $cadenaReducida .= "-";
  20.                 $i--;
  21.             } else {
  22.                 $cadenaReducida .= $cadena[$i];
  23.             }
  24.         }
  25.         // Agrega el extremo derecho
  26.         $cadenaReducida .= $cadena[strlen($cadena)-1];
  27.         return $cadenaReducida;
  28.     } else {
  29.         return $cadena;
  30.     }
  31. }

Un código honesto y magnifico, resulta muy halagador a la lectura la participación de este usuario.

Aunque claro, no supera con creces el tiempo de ejecución de sus oponentes si cumple su cometido, y lo realiza de manera ejemplar. Ya aquí se pone en practica el descarte del primer y último carácter, luego un bucle como scanner... presto!!
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #47 (permalink)  
Antiguo 11/07/2010, 15:27
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

Hidek1
Código PHP:
Ver original
  1. function reduce($text)
  2. {
  3.     $reduced = "";
  4.     $text = str_split($text);
  5.     foreach($text as $key => $value) {
  6.         $num1 = isset($text{$key+1}) ? ord($text{$key+1}) : 0;
  7.         $num2 = ord($value) + 1;
  8.         $reduced .= $value;
  9.         if($num1 == $num2) {
  10.             $reduced .= '##';
  11.             continue;
  12.         }
  13.         elseif($num1 == ($num2 - 2)) {
  14.             $reduced .= '@@';
  15.             continue;
  16.         }
  17.     }
  18.     $reduced = preg_replace('/(#[a-z]#|@[a-z]@)+/', '-', $reduced);
  19.     return str_replace(array('@', '#'), '', $reduced);
  20. }

¿Que se creen?

Pues este no es el código mas corto, lamentablemente. Curioso realmente, la implementación resulta correcta y extraña.

Que mas les puedo decir... segundo lugar en tamaño del script, y segundo lugar en ejecución de código... ¿pues que le pasa a este muchacho??
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.

Última edición por pateketrueke; 11/07/2010 a las 15:34 Razón: código correcto
  #48 (permalink)  
Antiguo 11/07/2010, 15:31
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

quike88
Código PHP:
Ver original
  1. function reduce($string)
  2. {
  3.     $res=$string[0]; //cadena donde se guardara el resultado, le asigno inicialmente el 1er caracter de la cadena
  4.     $flag=0; //en el caso de que exista la secuencia se pone en 1, para que asi, si es de mas 3 letras, no se repita el '-'
  5.     $longitud=strlen($string)-1; //longitud de la cadena -1, ya que el 1ro caracter y el ultimo los pongo directamente
  6.     for($i=1;$i<$longitud;$i++)
  7.     {
  8.     //verifico si el valor ascii - 1 es igual al del caracter anterior, y sumando 1 si es igual al proximo, y luego al revez por si la secuencia es reversa.
  9.         if( (ord($string[$i])-1==ord($string[$i-1]) and ord($string[$i])+1==ord($string[$i+1])) or (ord($string[$i])+1==ord($string[$i-1]) and ord($string[$i])-1==ord($string[$i+1])) ) {
  10.             if($flag==0){
  11.                 $res.='-';
  12.                 $flag=1;
  13.             }
  14.         }
  15.         else {
  16.             $res.=$string[$i];
  17.             $flag=0;
  18.         }
  19.     }
  20.     $res.=$string[$i];
  21.     return $res;
  22. }

Bingo!!

Este si es el código mas breve, sin embargo falla en cadenas menores a tres caracteres... ;)

Ahora, tomando en cuenta algunos factores para resumir la abstracción de la solución... este código pudo ser aún mas reducido, igual que el nombre de la función... reduce()
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #49 (permalink)  
Antiguo 11/07/2010, 21:52
 
Fecha de Ingreso: septiembre-2009
Ubicación: Neuquén
Mensajes: 142
Antigüedad: 10 años, 1 mes
Puntos: 12
Respuesta: [Desafío PHP] Función reduce()

Pucha llegue tarde

Solo para saber como me fue... @pateketrueke ¿Me tomarías el tiempo de mi reduce()? :D Lo haría yo, pero no se como lo has echo...

Aca dejo mi código, no lo mando por PM porque ya termino el desafío...

Lo hagas o no, gracias de todas formas :D

Utilize: strlen() y ord()

Código PHP:
Ver original
  1. <?php
  2.  
  3. function reduce($text) {
  4.    
  5.     // Tamaño de la cadena
  6.     $length = strlen($text);
  7.    
  8.     // Devolver la misma cadena si hay menos de 3 carácteres
  9.     if ($length < 3)
  10.         return $text;
  11.    
  12.     // Arreglo con el valor ASCII de cada carácter
  13.     $chars = array();
  14.    
  15.     for ($i = 0; $i < $length; $i++)
  16.         $chars[] = ord($text[$i]);
  17.    
  18.     $char = 0; // Carácter a verificar
  19.     $output = ''; // Salida
  20.     $previous = $current = $next = $range_start = $num_range_chars = $order = 0;
  21.    
  22.     do {
  23.        
  24.         $previous = $chars[$char - 1]; // Carácter anterior
  25.         $current = $chars[$char]; // Carácter actual
  26.         $next = $chars[$char + 1]; // Carácter siguiente
  27.        
  28.         // Verificar si ya estamos dentro de un rango
  29.         if ($range_start) {
  30.            
  31.             // Si el carácter anterior es mayor o menor
  32.             // (De acuerdo al orden de los carácteres)
  33.             // es igual al actual, marcar que el carácter actual
  34.             // está dentro de un rango de carácteres
  35.             if (($previous + $order) == $current) {
  36.                 ++$num_range_chars;
  37.             } else {
  38.                
  39.                 // Si hemos encontrado un carácter que no pertenece
  40.                 // al rango que estamos analizando, y el rango actual
  41.                 // tiene menos de 3 carácteres, agregamos el carácter anterior
  42.                 // a salida y continuamos (Ya que si estamos analizando un rango,
  43.                 // y solo encontramos 2 carácteres, el segundo nunca se agregó)
  44.                 if ($num_range_chars == 2)
  45.                     $output.= $text[$char - 1];
  46.                
  47.                 // Si el carácter actual, no esta dentro del rango,
  48.                 // pero pudimos terminar de analizar el rango actual,
  49.                 // agregamos el último carácter a salida
  50.                 if ($num_range_chars > 2)
  51.                     $output.= '-' .$text[$char - 1];
  52.                
  53.                 // Reseteamos las variables de rango
  54.                 $range_start = $num_range_chars = 0;
  55.             }
  56.         }
  57.        
  58.         // Si entre el carácter anterior, actual y el siguiente forman una cadena casi palíndromo
  59.         // Ej.: aba, oao, bab (Pero NO aaa, bbb, ccc, etc.)
  60.         // Nos aseguramos de terminar el rango que estamos analizando correctamente
  61.         // para seguir con el siguiente y detectamos el nuevo orden: decreciente o ascendente
  62.         if ($previous != $current && $next != $current && $previous == $next) {
  63.            
  64.             // Señalar final del rango actual, si estamos en uno
  65.             if ($num_range_chars > 2)
  66.                 $output.= '-';
  67.            
  68.             // Agregar carácter a salida
  69.             $output.= $text[$char];
  70.            
  71.             // Marcar comienzo de nuevo rango
  72.             $range_start = $current;
  73.             $num_range_chars = 1;
  74.            
  75.             // Lo mísmo que en la línea 101
  76.             if ($current < $next)
  77.                 $order = 1;
  78.             if ($current > $next)
  79.                 $order = -1;
  80.             if ($current == $next)
  81.                 $range_start = $num_range_chars = 0;
  82.         }
  83.        
  84.         // Comenzar a analizar un rango de carácteres
  85.         if (!$range_start) {
  86.            
  87.             // Agregar carácter a salida
  88.             $output.= $text[$char];
  89.            
  90.             // Fijar comienzo del rango de carácteres
  91.             $range_start = $current;
  92.            
  93.             // Marcar carácter que comienza el rango
  94.             ++$num_range_chars;
  95.            
  96.             // Si hay un carácter despues del actual,
  97.             // verificamos si es mayor o menor al actual
  98.             // para fijar el orden: decreciente o ascendente
  99.             // Si el siguiente carácter es el mismo,
  100.             // Reseteamos las variables que marcan un rango
  101.             if ($next) {
  102.                 if ($current < $next)
  103.                     $order = 1;
  104.                 if ($current > $next)
  105.                     $order = -1;
  106.                 if ($current == $next)
  107.                     $range_start = $num_range_chars = 0;
  108.             }
  109.         }
  110.        
  111.         // Pasamos al carácter siguiente
  112.         ++$char;
  113.        
  114.         // Si hemos llegado al final de la cadena,
  115.         // completamos la salida correctamente
  116.         if ($char == $length && $num_range_chars > 2)
  117.             $output.= '-' .$text[$char - 1];
  118.        
  119.     } while ($char < $length);
  120.    
  121.     // Devolver salida de carácteres
  122.     return $output;
  123. }
  124.  
  125. ?>

¡Saludos!

Última edición por Nisrokh; 11/07/2010 a las 22:05
  #50 (permalink)  
Antiguo 18/07/2010, 21:33
Colaborador
 
Fecha de Ingreso: octubre-2009
Ubicación: Tokyo - Japan !
Mensajes: 3.867
Antigüedad: 10 años
Puntos: 334
De acuerdo Respuesta: [Desafío PHP] Función reduce()



Gracias a todos los que concursaron... ( Y por los que votaron por mi código claro esta )
Espero que se entusiasmen de igual forma para el próximo reto... Porque ahí le pondré más empeño aun...

Saludos y gracias en especial a pateketrueke y a los que organizaron todo esto
__________________
More about me...
~ @rhyudek1
~ Github
  #51 (permalink)  
Antiguo 19/07/2010, 14:46
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 11 años, 7 meses
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

Finalmente la encuesta ha cerrado, y los resultados parecen apuntar a Hidek1 como el código mas favorecido...

Esta fue una competencia corta, divertida y realmente educativa. Lo único que me resta decir es: gracias a todos, y por favor... discutamos al respecto para así poder en marcha otros desafíos para la comunidad, que como saben, siempre esta dispuesta a colaborar.

Gracias.
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #52 (permalink)  
Antiguo 19/07/2010, 15:00
Avatar de GatorV
$this->role('moderador');
 
Fecha de Ingreso: mayo-2006
Ubicación: /home/ams/
Mensajes: 38.567
Antigüedad: 13 años, 5 meses
Puntos: 2135
Respuesta: [Desafío PHP] Función reduce()

En efecto fue un buen reto, ahora a ir por el siguiente y buscar lo mejor.

Reto Cerrado

Etiquetas: alfabetico, cadenas, competencia, compresion, desafío, medio, orden, reduce, reto, scripting, juegos
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Tema Cerrado

SíEste tema le ha gustado a 23 personas




La zona horaria es GMT -6. Ahora son las 05:46.