Soy nuevo en C # y Linq. Tengo un problema para eliminar registros duplicados. Necesito eliminar registros duplicados para aquellos que no tienen Dept. A continuación se muestra un ejemplo rápido con una lista de empleados

 private static void Main()
    {
        List<Employee> empList = new List<Employee>();

        empList.Add(new Employee() { ID = 1, Name = "John", Age=23, Dept='computer'});
        empList.Add(new Employee() { ID = 2, Name = "Mary", Age=25, Dept='computer'});
        empList.Add(new Employee() { ID = 3, Name = "Amber",Age=23, Dept=''});
        empList.Add(new Employee() { ID = 4, Name = "Kathy",Age=25, Dept=''});
        empList.Add(new Employee() { ID = 5, Name = "Lena", Age=27, Dept='computer'});
        empList.Add(new Employee() { ID = 6, Name = "John", Age=28, Dept=''});
        empList.Add(new Employee() { ID = 7, Name = "Kathy",Age=27, Dept='Tester'});
 empList.Add(new Employee() { ID = 8, Name = "John", Age=23, Dept='computer'});
        var dup = empList
            .GroupBy(x => new { x.FName })
            .Select(group => new { Name = group.Key, Count = group.Count() })
            .OrderByDescending(x => x.Count);

        foreach (var x in dup)
        {
            Response.Write(x.Count + " " + x.Name);
        }
    }
    class Employee
    {
        public int ID { get; set; }
        public string FName { get; set; }
        public int Age { get; set; }
        public char Dept { get; set; }
    }

El resultado final se parece a este ejemplo de salida: -

    empList.Add(new Employee() { ID = 1, Name = "John", Age=23, Dept='computer'});
        empList.Add(new Employee() { ID = 2, Name = "Mary", Age=25, Dept='computer'});
        empList.Add(new Employee() { ID = 3, Name = "Amber",Age=23, Dept=''}); 
        empList.Add(new Employee() { ID = 5, Name = "Lena", Age=27, Dept='computer'});
        empList.Add(new Employee() { ID = 7, Name = "Kathy",Age=27, Dept='Tester'});
 empList.Add(new Employee() { ID = 8, Name = "John", Age=23, Dept='computer'});

Necesito eliminar esos registros duplicados de aquellos que no tienen departamento.

Los registros duplicados de la condición 1 vendrán varias veces, pero un solo registro que no tiene un departamento que debería eliminarse. y el registro restante se mostrará en la salida

-3
gw0 6 ene. 2017 a las 16:53

5 respuestas

La mejor respuesta

Como la ID es única, puede usar este enfoque (Dept parece ser una cadena):

var empDupNoDepartment = empList
    .GroupBy(x => String.IsNullOrEmpty(x.Dept) ? int.MinValue : x.ID)
    .Select(group => group.First())
    .ToList();

Esto mantiene solo al primer empleado con Dept vacío.

1
Tim Schmelter 6 ene. 2017 a las 14:00

Lo que tienes aquí es un ejemplo de por qué el nombre de alguien es una clave primaria terrible para cualquier cosa.

Todos los valores:

var hasDept = empList.Where(x=>x.Dept != null && x.Dept.Trim() != string.Empty).ToList();

Valores distintos:

var hasDept =  empList.Where(x=>x.Dept != null && x.Dept.Trim() != string.Empty).Distinct().ToList();

Esos te darán los que tienen un departamento. Si también desea obtener los que no tienen uno, pero no tienen una entrada duplicada que tenga un departamento, la forma más fácil es probablemente:

var noDept = empList.Where(x=>x.Dept == null || x.Dept.Trim() == string.Empty).Distinct().ToList()  //gets all the ones with no dept

var all = noDept;
foreach(var e in all)
{
        if(hasDept.Where(x.Name == e.Name).Count == 0)
           all.Add(e);
}
-1
CDove 6 ene. 2017 a las 14:06
from e in empList
group e by e.Name into g
select g.FirstOrDefault(e => !String.IsNullOrEmpty(e.Dept)) ?? g.First();

Simplemente agrupe por Nombre y seleccione el primer empleado con el Departamento o solo el primer empleado.

Salida:

[
  { "ID": 1, "Name": "John", "Age": 23, "Dept": "computer" },
  { "ID": 2, "Name": "Mary", "Age": 25, "Dept": "computer" },
  { "ID": 3, "Name": "Amber", "Age": 23,"Dept": "" },
  { "ID": 7, "Name": "Kathy", "Age": 27, "Dept": "Tester" },
  { "ID": 5, "Name": "Lena", "Age": 27, "Dept": "computer" }
]

Si desea mantener todas las entradas con un departamento no vacío, entonces

Func<Employee, bool> hasDept = e => !String.IsNullOrEmpty(e.Dept);
var result = empList
       .GroupBy(e => e.Name)
       .SelectMany(g => g.Any(hasDept) ? g.Where(hasDept) : g.Take(1));

Sintaxis de consulta:

from e in empList
group e by e.Name into g
from e in g.Any(hasDept) ? g.Where(hasDept) : g.Take(1)
select e;

Salida:

[
  { "ID": 1, "Name": "John", "Age": 23, "Dept": "computer" },
  { "ID": 8, "Name": "John", "Age": 23, "Dept": "computer" },  <== difference
  { "ID": 2, "Name": "Mary", "Age": 25, "Dept": "computer" },
  { "ID": 3, "Name": "Amber", "Age": 23,"Dept": "" },
  { "ID": 7, "Name": "Kathy", "Age": 27, "Dept": "Tester" },
  { "ID": 5, "Name": "Lena", "Age": 27, "Dept": "computer" }
]
0
Sergey Berezovskiy 6 ene. 2017 a las 14:33

Crea esta clase:

class Dept
{
    public int Count { get; set; }
    public string Name { get; set; }
    public List<Employee> Employees { get; set; }
}

Y aquí está la consulta:

var dup = empList
    .GroupBy(x => new { x.Name })

    // Employees with duplicate name
    .Select(group => new { Emps = group.Select(x => x)})

    // From duplicates select only those that have a department 
    .SelectMany(x => {
        var emps = x.Emps.Where(y => !string.IsNullOrWhiteSpace(y.Dept));
        var employeesWithDept = emps.GroupBy(g => g.Name );


        IEnumerable<Dept> a = 
        employeesWithDept.Select(g => new Dept { Employees = g.ToList(), Name = g.Key.ToString(), Count = g.Count()});
        return a;
    })
    .OrderByDescending(x => x.Count);
0
CodingYoshi 6 ene. 2017 a las 14:58

No estoy seguro de eso, pero si solo desea eliminar a un empleado del Departamento vacío con un Linq, debería poder hacer:

empList = empList.Where(Dept => !string.IsNullOrWhiteSpace(Dept)).Distinct().ToList()

Atentamente !

-2
JoJa 6 ene. 2017 a las 14:01