Условное объединение двух коллекций с LINQ-to-Objects - PullRequest
0 голосов
/ 02 февраля 2012

Мне нужна помощь в поиске наиболее эффективного способа объединения двух коллекций в памяти с LINQ-to-Objects. В моем случае это не простое соединение или конкат, потому что некоторые элементы должны быть исключены на основе значения свойства.

Давайте использовать следующий пример (не очень реалистичный, но он иллюстрирует то, что мне нужно):

public abstract class Person
{
    public String Name { get; set; }
}

public class Employee : Person
{
    public DateTime? TerminationDate { get; set; }
}

public class Customer : Person
{
    ...
}

Обратите внимание, что Сотрудник также может быть Заказчиком.

У меня есть список сотрудников и список клиентов, и я хочу создать список всех лиц, следуя этим правилам:

  1. Все клиенты, которые не являются сотрудниками
  2. Все сотрудники, которые не являются также клиентами и не уволены (TerminationDate == null)
  3. Все лица, которые являются одновременно клиентами и сотрудниками, так и не уволены (TerminationDate == null)

Какой самый эффективный способ сделать это?

Ответы [ 2 ]

0 голосов
/ 06 февраля 2012

Хотя пример Джеймса не обязательно неверен, он немного сложнее, на который я надеялся, и он неполон, поскольку мне нужен один список в качестве конечного результата.

Не уверен, что это лучшее решение, либо, но вот что я придумал:

public abstract class Person
{
    public String Name { get; set; }

    public override Boolean Equals(Object other)
    {
        var otherPerson = other as Person;

        if (otherPerson == null)
            return false;

        return Name.Equals(otherPerson.Name, StringComparison.OrdinalIgnoreCase);
    }
}

public class Employee : Person
{
    public DateTime? TerminationDate { get; set; }
}

public class Customer : Person
{
    ...
}


public class People
{
    private IEnumerable<Customer> Customers;
    private IEnumerable<Employee> Employees;

    public IEnumerable<Person> GetCurrentPeople()
    {
        // Find all customers that are not employees
        var onlyCustomers = Customers.Except(Employees);

        // We only want employees that have not been terminated
        var currentEmployees = Employees.Where(e => e.TerminationDate == null);

        // Find all customers that are also employees
        var customerAndEmployees = currentEmployees.Intersect(Customers);

        // Now deal with employees that are not customers
        var onlyEmployees = currentEmployees.Except(Customers);

        // Join the lists together
        var mergedRules = onlyCustomers.Concat(onlyEmployees).Concat(customerAndEmployees);

        return mergedRules;
    }
}
0 голосов
/ 05 февраля 2012

Трудно сказать наверняка, но если предположить, что Джон согласен с сопоставлением имен, то имеет ли это концептуальный смысл?

Обратите внимание, что в настоящее время выполняется несколько итераций, поэтому я обычно добавляю ToArray иликак в некоторых местах, но я не хотел добавлять это в этот код, пытаясь проверить концептуальный бит.

var allPeople = ...;

var customers = allPeople.OfType<Customer>();
var employees = allPeople.OfType<Employee>();

var employeeNames = new HashSet(employees.Select(p => p.Name));
var customerNames = new HashSet(employees.Select(p => p.Name));

// list item #1
var customersNotEmployees = customers
    .Where(c => employeeNames.Contains(c.Name) == false);

// will be used by #2 and #3
var employeesNotTerminated = employees
    .Where(e => e.TerminationDate == null);

// list item #2
var employeesNotCustomersAndNotTerminated = employeesNotTerminated
    .Where(e => customerNames.Contains(e.Name) == false);

// list item #3
var employeesAndCustomersAndNotTerminated = employeesNotTerminated
    .Where(e => customerNames.Contains(e.Name) == true);
...