el Guille, la Web del Visual Basic, C#, .NET y más...

Buscar un elemento y si no está, usar el anterior

 
Publicado el 17/Ago/2010
Actualizado el 17/Ago/2010
Autor: Guillermo 'guille' Som

Buscar un elemento y si no está, usar el anterior... En este ejemplo he usado LINQ para realizar la búsqueda con Where y accediendo al elemento por medio del método extensor Last.



 

El problema:

Nuevamente, este "truco" viene a raíz de una pregunta en mis foros, en la que se decía que como se puede buscar (en una lista, colección, base de datos, etc.) de forma que si no se encuentra lo buscado, se devuelva el que esté anterior en el orden, por ejemplo, si tenemos estas palabras: Al, Alameda y Altanero, y buscamos Almacen, que si no está, que devuelva Alameda, que es la que está antes de donde debería estar Almacen.

 

La solución:

Si esto lo hacemos con LINQ podríamos buscar la palabra indicada, y en caso de que no exista, hacer una nueva búsqueda, pero esta vez buscando las que sean menores, es decir, estén antes en orden alfabético (ni que decir tiene que esto sólo funcionará si la lista en la que buscamos está clasificada).

Teniendo la colección del tipo Cliente que ya vimos en el truco de cómo "Buscar datos con LINQ sin tener en cuenta mayúsculas/minúsculas", podríamos hacer algo como lo que te muestro un poco más abajo.

 

Nota:
En este ejemplo se utiliza una colección generic del tipo List(Of Cliente) o List<Cliente>, estos links te llevarán al código para crear esa colección, tanto para Visual Basic como para C#.

Debido a que se utilizan instrucciones de LINQ, este código solamente es válido para versiones de .NET Framework igual o superior a la 3.5.
En el caso de la clase Cliente para Visual Basic sólo es válido para la versión 2010, salvo que definas las propiedades de forma "habitual".

 

en Visual Basic:

' Buscar el anterior más parecido al indicado (si no está el buscado)
Private Sub consultaParecida(ByVal txtConsulta As String)
    Console.WriteLine("Buscando: {0}", txtConsulta)

    ' Puede que lo usemos varias veces
    Dim conLower = txtConsulta.ToLower()

    Dim resp = From cli In clis _
               Where cli.Apellidos.ToLower = conLower _
               Select cli

    If resp.Count = 0 Then
        ' Buscar el anterior
        resp = From cli In clis _
               Where cli.Apellidos.ToLower < conLower _
               Select cli

        ' Si se quiere busca sólo los que empiecen con la misma letra
        resp = From cli In clis _
               Let apeLower = cli.Apellidos.ToLower
               Where apeLower.StartsWith(conLower.Substring(0, 1)) _
               AndAlso apeLower < conLower _
               Select cli
    End If

    If resp.Count > 0 Then
        Dim cli2 = resp.Last
        Console.WriteLine("{0}, {1}", cli2.Apellidos, cli2.DNI)
    Else
        Console.WriteLine("No se ha encontrado nada")
    End If

End Sub

 

en C#:

// Buscar el anterior más parecido al indicado (si no está el buscado)
static void consultaParecida(string txtConsulta)
{
    Console.WriteLine("Buscando: {0}", txtConsulta);

    // Puede que lo usemos varias veces
    var conLower = txtConsulta.ToLower();

    var resp = from cli in clis
               where cli.Apellidos.ToLower() == conLower
               select cli;

    // Count es un método...
    if (resp.Count() == 0)
    {
        // Nota:
        //  Ya no lo recordaba (ya que supongo que lo sabría)
        //  de que en C# no están sobrecargados los operadores < ni >
        //  para la clase String.
        //  Por tanto, hay que usar string.Compare (o CompareTo)
        //

        // Buscar el anterior
        resp = from cli in clis
               where string.Compare(cli.Apellidos.ToLower(), conLower) < 0
               select cli;

        // Si se quiere busca sólo los que empiecen con la misma letra
        resp = from cli in clis
               let apeLower = cli.Apellidos.ToLower()
               where apeLower.StartsWith(conLower.Substring(0, 1))
                  && apeLower.CompareTo(conLower) < 0
               select cli;
    }

    if (resp.Count() > 0)
    {
        var cli2 = resp.Last();
        Console.WriteLine("{0}, {1}", cli2.Apellidos, cli2.DNI);
    }
    else
    {
        Console.WriteLine("No se ha encontrado nada");
    }

}


 

El truco está en usar el método extensor Last para acceder al último elemento que hemos obtenido, en el caso de que encontremos lo que buscamos, el último será el que buscamos; y en caso de que se cumpla la segunda consulta de LINQ, el último será precisamente el que tendría que estar antes del que buscamos.

 

Espero que te sea de utilidad.

Nos vemos.
Guillermo

 


Espacios de nombres usados en el código de este artículo:

System.Linq
 


Código de ejemplo (comprimido):

No hay nada que descargar...


 


La fecha/hora en el servidor es: 23/12/2024 19:00:43

La fecha actual GMT (UTC) es: 

©Guillermo 'guille' Som, 1996-2024