Rendimiento de arboles de expresión.




 Mi entendimiento actual es que el código 'codificado por hardware' es el siguiente: 


```
publicÂ intÂ Add(intÂ x,Â intÂ y) {returnÂ xÂ +Â y;}

```
  siempre se desempeñará mejor que el código de árbol de expresiones como este: 


```
Expression<Func<int,Â int,Â int>>Â addÂ =Â (x,Â y)Â =>Â xÂ +Â y; 
varÂ resultÂ =Â add.Compile()(2,Â 3);

varÂ xÂ =Â Expression.Parameter(typeof(int)); 
varÂ yÂ =Â Expression.Parameter(typeof(int)); 
returnÂ (Expression.Lambda(Expression.Add(x,Â y),Â x,Â y).
    Compile()Â asÂ Func<int,Â int,Â int>)(2,Â 3);

```
  ya que el compilador tiene más información y puede dedicar más esfuerzo a optimizar el código si lo compila en tiempo de compilación. ¿Es esto generalmente cierto?
**Compilacion** 

 La llamada a `Expression.Compile` pasa exactamente por el mismo proceso que cualquier otro código .NET que su aplicación contenga en el sentido de que: 

* Se genera el código IL
* El código IL está JIT-ted al código de máquina

 (se omite el paso de análisis porque ya se creó un árbol de expresión y no es necesario generarlo a partir del código de entrada) 

 Puede mirar el [código fuente](http://referencesource.microsoft.com/#System.Core/Microsoft/Scripting/Compiler/LambdaCompiler.cs) del compilador de expresiones para verificar que efectivamente se genera el código IL. 

 **Mejoramiento** 

 Tenga en cuenta que casi toda la optimización realizada por el CLR se realiza en el paso JIT, no desde la compilación del código fuente de C #. Esta optimización también se realizará al compilar el código IL de su delegado lambda a código máquina. 

 **Su ejemplo** 

 En su ejemplo, está comparando manzanas y naranjas. El primer ejemplo es una definición de método, el segundo ejemplo es código de tiempo de ejecución que crea un método, lo compila y lo ejecuta. El tiempo que lleva crear / compilar el método es mucho más largo que ejecutarlo realmente. Sin embargo, puede mantener una instancia del método compilado después de la creación. Cuando haya hecho eso, el rendimiento de su método generado debería ser idéntico al del método C # original. 

 Considere este caso: 


```
private static int AddMethod(int a, int b)
{
    return a + b;
}

Func<int, int, int> add1 = (a, b) => a + b;
Func<int, int, int> add2 = AddMethod;

var x = Expression.Parameter(typeof (int));
var y = Expression.Parameter(typeof (int));
var additionExpr = Expression.Add(x, y);
Func<int, int, int> add3 = 
              Expression.Lambda<Func<int, int, int>>(
                  additionExpr, x, y).Compile();
//the above steps cost a lot of time, relatively.

//performance of these three should be identical
add1(1, 2);
add2(1, 2);
add3(1, 2);

```
  Entonces, la conclusión que se puede sacar es: el código IL es código IL, sin importar cómo se genere, y las expresiones Linq generan código IL.
No he entendido la pregunta. No sé si te refieres a que si, por ejemplo, en un registro nuevo pusieras el código de un producto que ya está en un registro previo, no "rellene" ese registro y las cantidades se las sume al registro que ya está, o si por el contrario, que en un campo al que para el ejemplo llamaremos TotalProducto, te vaya "arrastrando" la suma de las cantidades de ese producto. <p>los iconos son notoriamente ineficaces como etiquetas, y son muy difíciles de interpretar correctamente sin capacitación o experiencia. para la mayoría de las situaciones, los usuarios aprenden mejor las interpretaciones correctas solo con texto que con íconos solos. <sub>ver: wiedenbeck, s (1999). el uso de iconos y etiquetas en un programa de aplicación de usuario final: un estudio empírico de aprendizaje y retención. comportamiento y tecnología de la información, 18 (2), p68-82.</sub></p><p>los íconos son especialmente malos para cualquier cosa abstracta, como factura u oferta, ya que las cosas abstractas generalmente no tienen una imagen visual sólida (tanto la factura como la oferta podrían representarse como documentos en papel, pero ¿cómo los distinguiría?). del mismo modo, los iconos son particularmente malos para las acciones (por ejemplo, guardar, publicar); es difícil mostrar claramente un proceso con una imagen. sí, los iconos se usan todo el tiempo en las barras de herramientas para las acciones, pero las barras de herramientas estaban destinadas a expertos, y sin embargo, los usuarios se confunden con frecuencia (en promedio, <a href="https://web.archive.org/web/20130207024524/http://www.humanfactors.com/downloads/askericarchivebusiness2004.asp">los usuarios conocen solo seis elementos de la barra de herramientas de word</a> después de usar word regularmente por <em> dos años </em>).</p><p>los iconos pueden ahorrar espacio sobre el texto, pero al precio del reconocimiento. para iconos pequeños, como 16x16 píxeles, es muy difícil para los usuarios incluso reconocer de qué se supone que son una imagen, y mucho menos qué se supone que representa la imagen. un usuario que conozco pensó que el icono de "disco" para guardar era una imagen de un televisor. (era lo suficientemente mayor como para saber qué era un disquete). personalmente utilicé word durante años pensando que el ícono track changes era una especie de rosetta stone estilizada. a los usuarios expertos les resulta más fácil <a href="http://www.uie.com/brainsparks/2006/02/20/orbitz-cant-get-a-date/">confíe en la posición física memorizada</a> de los controles de la barra de herramientas en lugar de las etiquetas de los iconos para elegir un control. los íconos más grandes (por ejemplo, al menos 32 por 32 píxeles) pueden ayudar al reconocimiento, pero ocupan tanto espacio que es mejor usar el espacio para una etiqueta de texto clara. si el espacio es limitado, a menudo es mejor usar texto abreviado que iconos.</p><p>es extraordinariamente difícil acertar con los íconos. no intente desarrollar un nuevo icono sin extensas iteraciones de pruebas de usuario. incluso entonces, puedes fallar. los diseñadores de microsoft intentaron todo para hacer íconos interpretables para la barra de herramientas de outlook antes <a href="http://blogs.msdn.com/jensenh/archive/2005/11/01/487661.aspx">renunciar y seguir con etiquetas de texto</a> en los controles clave.</p><p>las etiquetas de iconos también dificultan el soporte técnico (por ejemplo, "haga clic en la hoja amarilla con una marca de verificación azul", en lugar de "haga clic en" aceptar "").</p><p>como regla general, los íconos solo deben permitirse cuando se aplican al menos dos de las siguientes tres condiciones:</p><ol> <li> <p>el espacio es muy limitado (es decir, demasiado pequeño para texto solo).</p> </li> <li> <p>los iconos están estandarizados (por ejemplo, la imagen del disquete para guardar)</p> </li> <li> <p>el ícono representa un objeto con un fuerte atributo análogo físico o visual (por ejemplo, un ícono de impresora para acceder a los atributos de la impresora, o un rectángulo rojo para establecer un fondo de página rojo).</p> </li> </ol><p>la información sobre herramientas es necesaria para los iconos cuando se usan solos, pero son un mal sustituto de las etiquetas de texto. sus usuarios no deberían tener que usar su aplicación buscando cosas. el hecho de que las etiquetas de texto nunca necesiten información sobre herramientas gráficas es una pista bastante buena de que el texto es mejor que los iconos.</p><p>si el espacio lo permite, los iconos combinados con texto son los mejores. (creo que hubo investigaciones que muestran esto desde fines de la década de 1980, pero no puedo encontrarlo). el uso selectivo de iconos con texto hace que ciertos elementos se destaquen más o agreguen interés visual. también puede mejorar la escalabilidad de los elementos, pero las buenas etiquetas de texto también pueden hacerlo. se sabe que los usuarios piensan subjetivamente que una aplicación es más fácil si tiene íconos, incluso cuando en realidad no mejoran el rendimiento (ver wiedenbeck, 1999 citado anteriormente), por lo que esa es otra razón para combinar íconos y texto.</p><p>por lo general, veo el ícono arriba o a la izquierda de la etiqueta de texto. no creo que sea necesariamente inherentemente mejor que las alternativas, pero es una convención que también debes seguir si tienes controles uno al lado del otro para que el usuario pueda confiar en la experiencia para saber qué etiqueta de texto va con cada ícono.</p> <p>para comprender lo que hace <code>yield</code>, debe comprender qué <em>generadores</em> son. y antes de que lleguen los generadores <em>iterables</em>.</p><h2>iterables</h2><p>cuando creas una lista, puedes leer sus artículos uno por uno. la lectura de sus elementos uno por uno se llama iteración:</p><pre><code>&gt;&gt;&gt; mylist = [1, 2, 3] &gt;&gt;&gt; for i in mylist: ... print(i) 1 2 3 </code></pre><p><code>mylist</code> es un <em>iterable</em>. cuando usas una comprensión de lista, creas una lista, y por lo tanto una iterable:</p><pre><code>&gt;&gt;&gt; mylist = [x*x for x in range(3)] &gt;&gt;&gt; for i in mylist: ... print(i) 0 1 4 </code></pre><p>todo lo que puede usar &quot;<code>for... in...</code>&quot; en es iterable; <code>lists</code>, <code>strings</code>, archivos ...</p><p>estos iterables son útiles porque puede leerlos tanto como desee, pero almacena todos los valores en la memoria y esto no siempre es lo que desea cuando tiene muchos valores.</p><h2>generadores</h2><p>los generadores son iteradores, una clase de iterable<strong> solo puedes iterar una vez </strong>. los generadores no almacenan todos los valores en la memoria,<strong> generan los valores sobre la marcha </strong>:</p><pre><code>&gt;&gt;&gt; mygenerator = (x*x for x in range(3)) &gt;&gt;&gt; for i in mygenerator: ... print(i) 0 1 4 </code></pre><p>es igual, excepto que usaste <code>()</code> en lugar de <code>[]</code>. pero, usted<strong> no puede </strong>realizar <code>for i in mygenerator</code> por segunda vez, ya que los generadores solo se pueden usar una vez: calculan 0, luego se olvidan y calculan 1, y terminan de calcular 4, uno por uno.</p><h2>rendimiento</h2><p><code>yield</code> es una palabra clave que se usa como <code>return</code>, excepto que la función devolverá un generador.</p><pre><code>&gt;&gt;&gt; def creategenerator(): ... mylist = range(3) ... for i in mylist: ... yield i*i ... &gt;&gt;&gt; mygenerator = creategenerator() # create a generator &gt;&gt;&gt; print(mygenerator) # mygenerator is an object! &lt;generator object creategenerator at 0xb7555c34&gt; &gt;&gt;&gt; for i in mygenerator: ... print(i) 0 1 4 </code></pre><p>este es un ejemplo inútil, pero es útil cuando sabes que tu función devolverá un gran conjunto de valores que solo necesitarás leer una vez.</p><p>para dominar <code>yield</code>, debe comprender que<strong> cuando llama a la función, el código que ha escrito en el cuerpo de la función no se ejecuta. </strong>la función solo devuelve el objeto generador, esto es un poco complicado :-)</p><p>luego, su código continuará desde donde lo dejó cada vez que <code>for</code> usa el generador.</p><p>ahora la parte difícil:</p><p>la primera vez que <code>for</code> llama al objeto generador creado desde su función, ejecutará el código en su función desde el principio hasta que llegue a <code>yield</code>, luego devolverá el primer valor del bucle. luego, cada una de las otras llamadas ejecutará el bucle que ha escrito en la función una vez más y devolverá el siguiente valor, hasta que no haya ningún valor para devolver.</p><p>el generador se considera vacío una vez que se ejecuta la función, pero ya no golpea <code>yield</code>. puede ser porque el bucle llegó a su fin, o porque ya no satisfaces un <code>"if/else"</code>.</p><hr><h2>tu codigo explicado</h2><p>generador:</p><pre><code># here you create the method of the node object that will return the generator def \_get\_child\_candidates(self, distance, min\_dist, max\_dist): # here is the code that will be called each time you use the generator object: # if there is still a child of the node object on its left # and if distance is ok, return the next child if self.\_leftchild and distance - max\_dist &lt; self.\_median: yield self.\_leftchild # if there is still a child of the node object on its right # and if distance is ok, return the next child if self.\_rightchild and distance + max\_dist &gt;= self.\_median: yield self.\_rightchild # if the function arrives here, the generator will be considered empty # there is no more than two values: the left and the right children </code></pre><p>llamador:</p><pre><code># create an empty list and a list with the current object reference result, candidates = list(), [self] # loop on candidates (they contain only one element at the beginning) while candidates: # get the last candidate and remove it from the list node = candidates.pop() # get the distance between obj and the candidate distance = node.\_get\_dist(obj) # if distance is ok, then you can fill the result if distance &lt;= max\_dist and distance &gt;= min\_dist: result.extend(node.\_values) # add the children of the candidate in the candidates list # so the loop will keep running until it will have looked # at all the children of the children of the children, etc. of the candidate candidates.extend(node.\_get\_child\_candidates(distance, min\_dist, max\_dist)) return result </code></pre><p>este código contiene varias partes inteligentes:</p><ul> <li><p>el bucle se repite en una lista, pero la lista se expande mientras se repite el bucle :-) es una forma concisa de revisar todos estos datos anidados, aunque sea un poco peligroso, ya que puede terminar con un bucle infinito. en este caso, <code>candidates.extend(node.\_get\_child\_candidates(distance, min\_dist, max\_dist))</code> agota todos los valores del generador, pero <code>while</code> sigue creando nuevos objetos generadores que producirán valores diferentes de los anteriores ya que no se aplica en el mismo nodo.</p></li> <li><p>el método <code>extend()</code> es un método de objeto de lista que espera un iterable y agrega sus valores a la lista.</p></li> </ul><p>usualmente le pasamos una lista:</p><pre><code>&gt;&gt;&gt; a = [1, 2] &gt;&gt;&gt; b = [3, 4] &gt;&gt;&gt; a.extend(b) &gt;&gt;&gt; print(a) [1, 2, 3, 4] </code></pre><p>pero en tu código recibe un generador, lo cual es bueno porque:</p><ol> <li>no necesitas leer los valores dos veces.</li> <li>es posible que tenga muchos hijos y no quiera que todos se almacenen en la memoria.</li> </ol><p>y funciona porque a python no le importa si el argumento de un método es una lista o no. python espera iterables por lo que trabajará con cadenas, listas, tuplas y generadores. esto se llama tipificación de pato y es una de las razones por las que python es tan genial. pero esta es otra historia, para otra pregunta ...</p><p>puede detenerse aquí, o leer un poco para ver un uso avanzado de un generador:</p><h2>controlando el agotamiento de un generador.</h2><pre><code>&gt;&gt;&gt; class bank(): # let's create a bank, building atms ... crisis = false ... def create\_atm(self): ... while not self.crisis: ... yield "$100" &gt;&gt;&gt; hsbc = bank() # when everything's ok the atm gives you as much as you want &gt;&gt;&gt; corner\_street\_atm = hsbc.create\_atm() &gt;&gt;&gt; print(corner\_street\_atm.next()) $100 &gt;&gt;&gt; print(corner\_street\_atm.next()) $100 &gt;&gt;&gt; print([corner\_street\_atm.next() for cash in range(5)]) ['$100', '$100', '$100', '$100', '$100'] &gt;&gt;&gt; hsbc.crisis = true # crisis is coming, no more money! &gt;&gt;&gt; print(corner\_street\_atm.next()) &lt;type 'exceptions.stopiteration'&gt; &gt;&gt;&gt; wall\_street\_atm = hsbc.create\_atm() # it's even true for new atms &gt;&gt;&gt; print(wall\_street\_atm.next()) &lt;type 'exceptions.stopiteration'&gt; &gt;&gt;&gt; hsbc.crisis = false # the trouble is, even post-crisis the atm remains empty &gt;&gt;&gt; print(corner\_street\_atm.next()) &lt;type 'exceptions.stopiteration'&gt; &gt;&gt;&gt; brand\_new\_atm = hsbc.create\_atm() # build a new one to get back in business &gt;&gt;&gt; for cash in brand\_new\_atm: ... print cash $100 $100 $100 $100 $100 $100 $100 $100 $100 ... </code></pre><p><strong> nota: </strong>para python 3, use<code>print(corner\_street\_atm.\_\_next\_\_())</code> o <code>print(next(corner\_street\_atm))</code></p><p>puede ser útil para varias cosas como controlar el acceso a un recurso.</p><h2>itertools, tu mejor amigo.</h2><p>el módulo de itertools contiene funciones especiales para manipular iterables. ¿alguna vez desea duplicar un generador? ¿encadenar dos generadores? ¿agrupar valores en una lista anidada con una sola línea? <code>map / zip</code> sin crear otra lista?</p><p>entonces solo <code>import itertools</code>.</p><p>¿un ejemplo? veamos las posibles órdenes de llegada para una carrera de cuatro caballos:</p><pre><code>&gt;&gt;&gt; horses = [1, 2, 3, 4] &gt;&gt;&gt; races = itertools.permutations(horses) &gt;&gt;&gt; print(races) &lt;itertools.permutations object at 0xb754f1dc&gt; &gt;&gt;&gt; print(list(itertools.permutations(horses))) [(1, 2, 3, 4), (1, 2, 4, 3), (1, 3, 2, 4), (1, 3, 4, 2), (1, 4, 2, 3), (1, 4, 3, 2), (2, 1, 3, 4), (2, 1, 4, 3), (2, 3, 1, 4), (2, 3, 4, 1), (2, 4, 1, 3), (2, 4, 3, 1), (3, 1, 2, 4), (3, 1, 4, 2), (3, 2, 1, 4), (3, 2, 4, 1), (3, 4, 1, 2), (3, 4, 2, 1), (4, 1, 2, 3), (4, 1, 3, 2), (4, 2, 1, 3), (4, 2, 3, 1), (4, 3, 1, 2), (4, 3, 2, 1)] </code></pre><h2>entendiendo los mecanismos internos de iteración.</h2><p>la iteración es un proceso que implica iterables (implementación del método <code>\_\_iter\_\_()</code>) e iteradores (implementación del método <code>\_\_next\_\_()</code>). iterables son cualquier objeto de los que puede obtener un iterador. los iteradores son objetos que le permiten iterar en iterables.</p><p>hay más información al respecto en este artículo sobre <a href="http://effbot.org/zone/python-for-statement.htm">cómo funcionan <code>for</code> loops</a> .</p> En pocas palabras: LINQ to Entities no conoce la conversión de su tipo de ID a una cadena. 

 ¿Cuál es el tipo de `c.ID` ? ¿Hay alguna razón por la que sea un tipo para ID, pero otro para `ReferenzId` ? Si es posible, conviértalos en el mismo tipo, en cuyo punto ya no tendrá más problemas. No sé si hay otras formas de realizar conversiones en LINQ a Entidades (puede haber), pero la alineación de los tipos sería más clara. 

 Por cierto, esto realmente parece que es una combinación: 


```
var query = from c in db.Customers
            join a in db.Addresses on c.Id equals a.ReferenzId into addresses
            select new { Id = c.Id, Addresses = addresses };

```
  EDITAR: Para responder a su comentario: `ToString` aparece en IntelliSense porque el compilador no tiene una idea real de lo que va a significar su consulta ni de cómo se traducirá. Es perfectamente válido C #, y puede generar un árbol de expresiones válido. Es solo que EF no sabe cómo convertir ese árbol de expresiones en SQL. 

 Puede *intentar* usar `Convert.ToString(c.Id)` lugar de simplemente llamar a `c.Id.ToString()` ... <p>algunas consideraciones:</p><ol> <li>¿para qué sistema operativo es esto (o es para múltiples)?</li> <li>¿hay restricciones o límites conocidos en su jerarquía?</li> <li>¿existe alguna opción de búsqueda?</li> </ol><p>el número 1 es importante como notó ... porque mac finder sería extraño para la mayoría de los usuarios de windows.</p><p>no. 2 puede proporcionar asistencia también. p.ej. el buscador funciona bien si tiene un árbol poco profundo, pero si tiene 15-20 niveles de profundidad, se puede usar</p><p>no. 3 es un artículo de usabilidad. si no puedo ver rápidamente todo el árbol en menos de 5-10 segundos, se necesita una opción de búsqueda.</p><p>en general, creo que el "árbol" estándar es el más obvio para los usuarios. la jerarquía es físicamente visible, y solo es necesario abrir/explorar la rama de interés, pero puede abrir más de una rama para realizar comparaciones o búsquedas.</p><p>mi única otra sugerencia sería si tienes un espacio mínimo para trabajar, el paradigma de "profundización" del ipod funciona muy bien.</p><p><img src="https://i.stack.imgur.com/yoleu.jpg" alt="alt text"></p> Si te explicas, el problema es que la función se tendría que aplicar a cada ciertos rangos y dependiendo de los datos en las celdas se podrá o no sumar.  
No entiendo por qué pones datos en esta forma, lo siento un poco desordenado. Para cuestiones de análisis es mejor que los datos estén continuos. Si lo que tienes son grupos de datos puedes utilizar la función =Sumar. Si() o =Contar. Si().  
Cualquier cosa me mandas un ejemplo de tu archivo y trato de orientarte. hola [@juanbarriostk](/u/juanbarriostk) es probable que esos códigos se gestionan por lote.

saludos, OK. De movida te comento que no será sencillo, pero podemos resolvvero por aproximaciones sucesivas.  
Como me están faltando datos respecto al diseño de tu hoja. Supongo que la base de datos tiene cantidades irregulares de registros para cada persona, pero seguramente puedes saber cuantos tiene el de mayor cantidad de líneas. Asumo, además, que la base está ordenada por ID.  
Una combinación de las funciones INDICE y COINCIDIR funcionan en forma similar al BUSCARV. Pero en el caso que planteas -creo- sería la solución a tu problema.   
Vale decir que, si la función COINCIDIR encuentra el valor buscado (ID) en la primer columna traerá los datos en cada línea de acuerdo a la fila donde la fórmula se encuentre.   
Tal fórmula sería como esta:   
=INDICE(Hoja2!$C$5:$G$20;COINCIDIR($I$5;Hoja2!$C$5:$C$20;0)+FILA()-FILA($I$5);COLUMNA()-COLUMNA($I$5)+1)   
[Considera si sueles usar comas o punto y coma para separar argumentos de las funciones. Yo usé ";"]  
Está fórmula copiada en las celdas inferiores traerá los datos como quieres, pero adolece de un problema, necesitas saber de antemano cuántos registros tienes para el que estas buscando y contar con una cantidad igual de líneas de fórmulas de búsqueda.   
Para evitar ese problema, la siguiente fórmula agrega un control:   
=SI($I$5=INDICE(Hoja2!$C$5:$G$20;COINCIDIR($I$5;Hoja2!$C$5:$C$20;0)+FILA()-FILA($I$5);1);INDICE(Hoja2!$C$5:$G$20;COINCIDIR($I$5;Hoja2!$C$5:$C$20;0)+FILA()-FILA($I$5);COLUMNA()-COLUMNA($I$5)+1);"")   
INDICE muestra un dato de una matriz (C5:G20 de la hoja2) de acuerdo a las coordenadas de fila y columna que se le indique como argumentos.   
Para obtener la coordenada Fila usamos la función COINCIDIR en un rango (C5:C20 de Hoja2) de la misma altura (misma cantidad y ubicación de las líneas) que la base de búsqueda. Al número de fila así obtenido le agregará tantas líneas como diferencia halla entre la fila donde está la fórmula y la fila donde está el dato a buscar. Así, si la fórmula estuviera en la misma fila que el dato, tal diferencia será cero y, por lo tanto, traerá el dato de la misma fila.   
Al copiar esta celda y pegarla en la fila inferior, la diferencia será 1, por lo tanto traerá el valor de la fila siguiente de la base original. Y así sucesivamente.   
De igual modo, para identificar de qué columna traer el dato, restará la columna actual menos la primera.   
De esta manera, la misma fórmula copiada al resto del rango donde debe traer los valores servirá al propósito sin tener que modificarla.   
Aquí vale aclarar que, si no quieres todas las columnas, puedes especificarle exactamente qué columna necesitas, reemplazando la expresión COLUMNA()-COLUMNA($I$5)+1) por el número de la columna a mostrar  
El control que le agregué, verifica que en cualquier fila que se esté buscando se trate de la misma persona que se buscó originalmente.   
Lo único que tendrás que tener en cuenta es tener una cantidad de lineas de esta fórmula de búsqueda igual al mayor número de registros que pueda tener una persona.   
Por ejemplo, supongamos que buscar los datos de los hijos de cada empleado. Si hubiera un fecundo con 10 hijos, tendrás que tener 10 filas con aquella fórmula que te sugerí. Para los que tengan menos de 10, las celdas excedentes no mostrarán nada. Pero si hubiera uno con once o doce, sólo mostrará hasta el décimo.   
Por último, si -eventualmente- necesitaras otro set de estas fórmulas para buscar otro código en otro rango de la hoja "Datos" necesitarás, primero quitarle la referencia absoluta a la celda donde está e primer código (I5).   
Nota que, apropósitamente, todas las referencias a la linea del código dicen $I$5 de forma tal que siempre lean esa celda a cada uno de sus efectos.   
Lo que suelo hacer, entonces, es seleccionar todo el rango de fórmulas (4 columnas por 8 filas) y hago "Edición" | "Reemplazar..." En la casilla Buscar: coloco $I$5 y en la de reemplazar con escribo I5. Finalmente presiono "Reemplazar todo"   
Si bien todas las fórmulas modificadas siguen "apuntando" a la celda I5, esta es ahora una referencia relativa a tal celda. Esto permite que al copiarlas a otro rango lean una posición distinta a I5.   
Por ejemplo, si tu otro código a buscar estuviera en la celda I14 y copias este set de fórmulas a partir de esa misma fila, todas leerán los datos de la celda I14.   
Lo dicho: No es una tarea simple, pero si sigues cuidadosamente las instrucciones, llegarás al objetivo.  
- Ingresa al sitio www.porloschicos.com y, si quieres,   
presiona el botón de donación (es gratis).   
Confío en que lo harás. true.                          
--
mira si quisiste poner x en lugar de 0, entonces es el intervalo tal que x es menor o igual a 2, por lo tanto un intervalo del -∞ a 2, cerrado por la derecha (por que se incluye al dos).

(-∞ ; 2]    --> representación formal.


si quisiste decir todos los valores que están entre 0 y 2, debería ser expresado de otra manera, como esta: 0<= x <=2 o 0< x <=2, y dependiendo de como lo expreses (mayor o igual, o mayor que cero) va a ser la representación del intervalo.

[0; 2] --> mayor igual.

(0; 2] --> mayor. básicamente, se crea una función de interfaz:public interface func { public out apply(in in); } y, a continuación, pasar una subclase anónima a través de su método.su método se podría aplicar la función a cada elemento en el lugar:public static void applytolistinplace(list list, func f) { listiterator itr = list.listiterator(); while (itr.hasnext()) { t output = f.apply(itr.next()); itr.set(output); } } // ... list mylist = ...; applytolistinplace(mylist, new func() { public string apply(string in) { return in.tolowercase(); } }); o crear un nuevo list (básicamente la creación de una asignación de la lista de entrada a la de salida de la lista):public static list map(list in, func f) { list out = new arraylist(in.size()); for (in inobj : in) { out.add(f.apply(inobj)); } return out; } // ... list mylist = ...; list lowercased = map(mylist, new func() { public string apply(string in) { return in.tolowercase(); } }); que uno es preferible depende de su caso de uso. si la lista es muy grande, en lugar de la solución puede ser la única solución viable; si usted desea aplicar a muchas funciones diferentes a la misma lista original para hacer muchas otras listas, usted va a querer la map versión.