2011-02-23 23 views
23

tengo una lista muy larga de la identificación (números enteros) que representa todos los elementos que se encuentran actualmente en mi base de datos:Cómo restar una lista enorme de otra manera eficiente en C#

var idList = GetAllIds(); 

También tengo otro gran genérica lista con los elementos a añadir a la base de datos:

List<T> itemsToAdd; 

Ahora, me gustaría eliminar todos los elementos de la lista genérica cuyo ID está ya en la idList. Actualmente idList es una simple matriz y restar las listas de la siguiente manera:

itemsToAdd.RemoveAll(e => idList.Contains(e.Id)); 

Estoy bastante seguro de que podría ser mucho más rápido, por lo que los tipos de datos debería usar tanto para colecciones y lo que es la práctica más eficiente para restarlos?

¡Gracias!

+0

Me gustaría saber cómo transmitir/enumerar esto también, si es posible ... – drzaus

Respuesta

17

transformar temporalmente idList a un HashSet<T> y utilizar el mismo método, es decir:

items.RemoveAll(e => idListHash.Contains(e.Id)); 

que debería ser mucho más rápido

+1

Gracias - ¡eso funciona mucho más rápido y es lo que hice! – Shackles

2

Debe usar dos HashSet<int> s.
Tenga en cuenta que son únicos y no ordenados.

22

LINQ podría ayudar:

itemsToAdd.Except(idList) 

Su código es lento porque List<T>.Contains es O(n). Entonces, su costo total es O(itemsToAdd.Count*idList.Count).

Puede hacer idList en un HashSet<T> que tiene O(1).Contains. O simplemente use el método de extensión Linq .Except que lo hace por usted.

Tenga en cuenta que .Except también eliminará todos los duplicados del lado izquierdo. es decir, el nuevo int[]{1,1,2}.Except(new int[]{2}) dará como resultado {1} y el segundo 1 se eliminó. Pero supongo que no es un problema en su caso porque los ID son típicamente únicos.

+0

Tenga en cuenta que esto también excluirá cualquier duplicado de 'itemsToAdd'. Si eso es un problema depende de la OP (sospecho que no, ya que ellos están usando 'RemoveAll' en su ejemplo). – LukeH

+0

@LukeH Estaba editando eso en. – CodesInChaos

+0

+1 y gracias por la excelente explicación! Ahora construyo IdList como Hashset pero no puedo usar .Except() porque itemsToAdd es de tipo List/HashSet e idList es del tipo HashSet . Sin embargo, es mucho más rápido y satisface mis necesidades. – Shackles

5

Suponiendo las siguientes premisas son verdaderas:

  • idList y itemsToAdd no puede contener valores duplicados
  • está utilizando .NET Framework 4.0

Se puede usar un HashSet<T> esta manera:

var itemsToAddSet = new HashSet(itemsToAdd); 
itemsToAddSet.ExceptWith(idList); 

según la documentación del método ISet<T>.ExceptWith es bastante eficiente:

Este método es un O (n) la operación, donde n es el número de elementos en el otro parámetro.

En su caso n es el número de elementos en idList.

+0

El problema es que ItemsToAdd sería del tipo HashSet e idList es del tipo HashSet . Por lo tanto, no puedo llamar a ExceptWith en estos dos y necesito transformar IdList en un Hashset que consumiría mucha memoria. – Shackles

+0

'idList' no tiene que ser un' HashSet ', solo necesita crear un HashSet fuera de' itemsToAdd'. A continuación, pasará 'idList' a' HashSet .ExceptWith' como 'IEnumerable '. –

Cuestiones relacionadas