none
¿Me ayudan a afinar este filtro de una lista (explico)? RRS feed

  • Pregunta

  • Los elementos de la lista son del tipo ClaseNombres:

    Public Class ClaseNombres
       Public Property Id As Integer
       Public Property Nombre As String
       Public Property Total as Integer
    End Class
    
    Private Lista As ClaseNombres

    Suponiendo que los elementos de Lista tienen datos como estos:

    Juan Pérez

    Juan Fulano

    Juan

    Juan Pérez

    Juan Fulano

    Juan

    JUAN

    María

    María

    María Magdalena

    Deseo filtrar la lista anterior de manera que obtenga datos no repetidos y que en TOTAL se llene la cantidad de elementos agrupados y que Id contenga un número correlativo, algo así:

    ID............NOMBRE...............TOTAL

    1.............Juan....................3

    2.............Juan Fulano..........1

    3.............Juan Pérez............2

    4............María....................2

    5............María Magdalena.....1

    En otras palabras que cuente los repetidos. Con lo que tengo logro agrupar todos los nombres no repetidos y luego con un bucle relleno el ID con números correlativos, ¿No habrá forma de hacer todo en un solo comando? 

    ListaFiltrada = Lista.GroupBy(Function(Elemento) Elemento.Nombre).Select(Function(Elemento) Elemento.First).ToList

    (Si no es posible llenar el ID en un solo comando por lo menos llenar la columna TOTAL).



    • Editado James2016-2 viernes, 4 de diciembre de 2020 15:16
    viernes, 4 de diciembre de 2020 15:15

Respuestas

  • Deleted
    • Marcado como respuesta James2016-2 viernes, 4 de diciembre de 2020 18:11
    viernes, 4 de diciembre de 2020 17:05
  • mira otro modo

    Public Class Form1
    
        Dim lista1 As New List(Of ClaseNombres)()
        Dim lista2 As New List(Of String)()
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            ListBox1.Items.Clear()
            Call MyListData()
    
            For Each [Nombre] In lista1
                lista2.Add([Nombre].Nombre)
            Next
    
            Dim resultado = lista2.GroupBy(Function(x) x).Select(Function(y) New ClaseNombres() With {.Nombre = y.Key, .Total = y.Count()})
    
            Dim indice As Integer = 0
    
            For Each result In resultado
                ListBox1.Items.Add((String.Format("Id = {0}  Nombre = {1} Total = {2}", lista1(indice).Id, result.Nombre, result.Total)))
                indice += 1
            Next
        End Sub
    
        Private Structure ClaseNombres
            Public Id As Integer
            Public Nombre As String
            Public Total As Integer
        End Structure
    
    
        Private Sub MyListData()
            lista1.Add(New ClaseNombres With {.Id = 1, .Nombre = "Juan Pérez", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 2, .Nombre = "Juan Fulano", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 3, .Nombre = "Juan ", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 4, .Nombre = "Juan Pérez", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 5, .Nombre = "Juan Fulano", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 6, .Nombre = "Juan ", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 7, .Nombre = "JUAN", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 8, .Nombre = "Maria", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 9, .Nombre = "Maria", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 10, .Nombre = "Maria Magdalena", .Total = 0})
        End Sub
    End Class
    el codigo se ve largo porque puse todo junto

    • Marcado como respuesta James2016-2 viernes, 4 de diciembre de 2020 18:11
    viernes, 4 de diciembre de 2020 17:27
  • Deleted
    • Marcado como respuesta James2016-2 viernes, 4 de diciembre de 2020 19:31
    viernes, 4 de diciembre de 2020 19:00
  • Deleted
    • Marcado como respuesta James2016-2 viernes, 4 de diciembre de 2020 20:54
    viernes, 4 de diciembre de 2020 19:58

Todas las respuestas

  • Deleted
    • Marcado como respuesta James2016-2 viernes, 4 de diciembre de 2020 18:11
    viernes, 4 de diciembre de 2020 17:05
  • mira otro modo

    Public Class Form1
    
        Dim lista1 As New List(Of ClaseNombres)()
        Dim lista2 As New List(Of String)()
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            ListBox1.Items.Clear()
            Call MyListData()
    
            For Each [Nombre] In lista1
                lista2.Add([Nombre].Nombre)
            Next
    
            Dim resultado = lista2.GroupBy(Function(x) x).Select(Function(y) New ClaseNombres() With {.Nombre = y.Key, .Total = y.Count()})
    
            Dim indice As Integer = 0
    
            For Each result In resultado
                ListBox1.Items.Add((String.Format("Id = {0}  Nombre = {1} Total = {2}", lista1(indice).Id, result.Nombre, result.Total)))
                indice += 1
            Next
        End Sub
    
        Private Structure ClaseNombres
            Public Id As Integer
            Public Nombre As String
            Public Total As Integer
        End Structure
    
    
        Private Sub MyListData()
            lista1.Add(New ClaseNombres With {.Id = 1, .Nombre = "Juan Pérez", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 2, .Nombre = "Juan Fulano", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 3, .Nombre = "Juan ", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 4, .Nombre = "Juan Pérez", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 5, .Nombre = "Juan Fulano", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 6, .Nombre = "Juan ", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 7, .Nombre = "JUAN", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 8, .Nombre = "Maria", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 9, .Nombre = "Maria", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 10, .Nombre = "Maria Magdalena", .Total = 0})
        End Sub
    End Class
    el codigo se ve largo porque puse todo junto

    • Marcado como respuesta James2016-2 viernes, 4 de diciembre de 2020 18:11
    viernes, 4 de diciembre de 2020 17:27
  • mira otro modo

    Public Class Form1
    
        Dim lista1 As New List(Of ClaseNombres)()
        Dim lista2 As New List(Of String)()
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            ListBox1.Items.Clear()
            Call MyListData()
    
            For Each [Nombre] In lista1
                lista2.Add([Nombre].Nombre)
            Next
    
            Dim resultado = lista2.GroupBy(Function(x) x).Select(Function(y) New ClaseNombres() With {.Nombre = y.Key, .Total = y.Count()})
    
            Dim indice As Integer = 0
    
            For Each result In resultado
                ListBox1.Items.Add((String.Format("Id = {0}  Nombre = {1} Total = {2}", lista1(indice).Id, result.Nombre, result.Total)))
                indice += 1
            Next
        End Sub
    
        Private Structure ClaseNombres
            Public Id As Integer
            Public Nombre As String
            Public Total As Integer
        End Structure
    
    
        Private Sub MyListData()
            lista1.Add(New ClaseNombres With {.Id = 1, .Nombre = "Juan Pérez", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 2, .Nombre = "Juan Fulano", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 3, .Nombre = "Juan ", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 4, .Nombre = "Juan Pérez", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 5, .Nombre = "Juan Fulano", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 6, .Nombre = "Juan ", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 7, .Nombre = "JUAN", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 8, .Nombre = "Maria", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 9, .Nombre = "Maria", .Total = 0})
            lista1.Add(New ClaseNombres With {.Id = 10, .Nombre = "Maria Magdalena", .Total = 0})
        End Sub
    End Class
    el codigo se ve largo porque puse todo junto

    Muchas gracias.
    viernes, 4 de diciembre de 2020 18:10
  • Dim id = 0
    Dim ListaFiltrada = Lista.GroupBy(Function(Elemento) Elemento.Nombre, New Compara()).Select(Function(g)
                                               id += 1 : Return New ClaseNombres With {.Id = id, .Nombre = g.Key, .Total = g.Count} : End Function).ToList()
    
    '
    '
    '
    Public Class Compara
        Inherits EqualityComparer(Of String)
    
        Public Overrides Function Equals(x As String, y As String) As Boolean
            Return x.ToUpper = y.ToUpper
        End Function
    
        Public Overrides Function GetHashCode(obj As String) As Integer
            Return obj.ToUpper.GetHashCode
        End Function
    End Class

    Fijate que la expresión ocupa dos líneas, porque el lambda del select no me deja usar dos puntos en donde se corta.

    Fijate que el nombre asignado es el del primer elemento del grupo.

    Muchas gracias.
    viernes, 4 de diciembre de 2020 18:11
  • Walter, una consulta, ¿qué hace exactamente la función GetHasCode, por qué es necesario reemplazarla (overrides)?
    viernes, 4 de diciembre de 2020 18:41
  • Deleted
    • Marcado como respuesta James2016-2 viernes, 4 de diciembre de 2020 19:31
    viernes, 4 de diciembre de 2020 19:00
  • El algoritmo va creando una hashtable de cada objeto, por eso lo solicita. Es más eficiente comparar números, que comparar cadenas.

    Cuando dos objetos tienen diferente hash, son diferentes. Punto.

    Cuando dos objetos tienen el mismo hash, se llama a Equals para ver si son efectivamente iguales.

    El override es necesario porque nosotros necesitamos que Juan, JUAN, JUan y juAn, tengan el mismo hash. Si no hacemos un override, las cuatro strings tienen hashes diferentes.

    Si al método GroupBy no le pasamos el argumento Comparar, entonces vas a tener 6 grupos de objetos porque Juan y JUAN no quedarán juntos.

    Ah, OK, gracias nuevamente.
    viernes, 4 de diciembre de 2020 19:31
  • Deleted
    • Marcado como respuesta James2016-2 viernes, 4 de diciembre de 2020 20:54
    viernes, 4 de diciembre de 2020 19:58
  • Hola,

     

    gracias por confirmar que encontraste una respuesta a tu pregunta.

     

    Saludos cordiales

     

    Gabriel Castro

    viernes, 4 de diciembre de 2020 21:39
    Moderador