2010-09-07 12 views
8

Bir List<Users> var - Kullanıcıların bir Kullanıcı adı özelliği var.Listeden T özelliklerinin bir listesini almak için en iyi yol <T>

Bilmek istediğim şey - tüm Kullanıcı Listesinin List<string> numarasını almak ve yeni listemi oluşturmaktan daha iyi bir yol var mı?

+1

siz "daha iyi bir yol" da ne demek mi? LINQ kullanabilirsiniz, ancak bu aynı zamanda kapak altında da dönecektir. – Grzenio

cevap

22

Kullanım LINQ: Bunun gibi

List<string> usernames = users.Select(u => u.UserName).ToList(); 
+0

Kullanıcıların 4 veya daha az öğesi olmadıkça, SLAP'lerin yanıtına göre ConvertAll ile karşılaştırıldığında gereksiz bir şekilde savurganlık. –

4
var usernames = users.Select(u => u.Username).ToList(); 
12

: userNames liste users veya UserName s sonraki değişiklikleri yansıtacak olmayacağını

List<string> userNames = users.ConvertAll(u => u.UserName); 

Not.

5

Aslında bir List'e ihtiyacınız varsa, LINQ yöntemi yapabileceğiniz en iyi yöntemle ilgilidir (uygun bir kapasiteye sahip yeni bir Liste oluştururken marjinal bir hız artışı olabilir ve daha sonra eklenebilir, ancak bu değer düşük olabilir.

Düzenleme:. bunu yapacaksın Eğer liste büyük olabilir, özellikle eğer, ToList ardından değil SelectConvertAll kullanmak ConvertAll preallocates doğru boyuta önem performansının üzerine hangi kaynak listesinin boyutu ile büyür

Bunu yaptığınız gibi davranan bir salt okunur IList istiyorsanız, o zaman Bir dönüştürme liste sınıfı üzerinden t çok daha iyi bir performans: Bununla

public class ConvertingList<TSrc, TDest> : IList<TDest> 
{ 
    private readonly IList<TSrc> _inner; 
    private readonly Func<TSrc, TDest> _conv; 
    public ConvertingList(IList<TSrc> inner, Func<TSrc, TDest> conv) 
    { 
     _inner = inner; 
     _conv = conv; 
    } 
    public TDest this[int index] 
    { 
     get 
     { 
      return ReferenceEquals(null, _inner[index]) ? default(TDest) : _conv(_inner[index]); 
     } 
     set 
     { 
     throw new NotSupportedException("Readonly collection"); 
     } 
    } 
    public int Count 
    { 
     get 
     { 
     return _inner.Count; 
     } 
    } 
    public bool IsReadOnly 
    { 
     get 
     { 
     return true; 
     } 
    } 
    public int IndexOf(TDest item) 
    { 
     if(ReferenceEquals(item, null)) 
     { 
     for(int i = 0; i != Count; ++i) 
      if(ReferenceEquals(this[i], null)) 
      return i; 
     } 
     else 
     { 
     for(int i = 0; i != Count; ++i) 
      if(item.Equals(this[i])) 
      return i; 
     } 
     return -1; 
    } 
    public void Insert(int index, TDest item) 
    { 
     throw new NotSupportedException("Readonly collection"); 
    } 
    public void RemoveAt(int index) 
    { 
     throw new NotSupportedException("Readonly collection"); 
    } 
    public void Add(TDest item) 
    { 
     throw new NotSupportedException("Readonly collection"); 
    } 
    public void Clear() 
    { 
     throw new NotSupportedException("Readonly collection"); 
    } 
    public bool Contains(TDest item) 
    { 
     return IndexOf(item) != -1; 
    } 
    public void CopyTo(TDest[] array, int arrayIndex) 
    { 
     if(array == null) 
     throw new ArgumentNullException(); 
     if(arrayIndex < 0) 
      throw new ArgumentOutOfRangeException(); 
     if(array.Rank != 1 || array.Length < arrayIndex + Count) 
      throw new ArgumentException(); 
     foreach(TDest item in this) 
      array[arrayIndex++] = item; 
    } 
    public bool Remove(TDest item) 
    { 
     throw new NotSupportedException("Readonly collection"); 
    } 
    public IEnumerator<TDest> GetEnumerator() 
    { 
     foreach(TSrc srcItem in _inner) 
     yield return ReferenceEquals(null,srcItem) ? default(TDest) : _conv(srcItem) 
    } 
    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

, o zaman:

IList<string> userNames = new ConvertingList<User, string>(users, u => u.Username); 

adları salt okunur liste olarak davranır sabit zamanda yeni bir nesne oluşturur.

(Boş bir kullanıcıya karşı koruma, burada boş bir dizge döndürür, diğer davranışlar elbette sağlanabilir).

+0

Salt okunur liste sadece dönüştürme işlevinizin yürütülmesini geciktirir. Bu nedenle, muhtemelen sonunda alacağınız listeyi kullanacaksanız, kaydedilen zaman daha sonra gerekli olacaktır. Daha da kötüsü: Eğer listeyi iki kez döndürmek isterseniz, dönüştürme fonksiyonunuz tekrar tekrar çalıştırılır, böylece daha yavaş bir liste ortaya çıkar. Seçme kullanma seçeneğinin mikro optimizasyon olarak adlandırıldığını söyleyen insanlar, bu 10 ms'lik ekstraları fark etmeyeceklerdir. Ayrıca, Select, Microsoft tarafından desteklenmektedir, bu nedenle daha yeni çerçeve sürümlerindeki herhangi bir optimizasyon doğrudan kodunuza fayda sağlayacaktır. – Arcturus

+0

@Arcturus, readonly listesi, kullanıma bağlı olarak 'ConvertAll' seçeneğinden daha iyi veya daha kötüdür; Eğer büyüklüğü almam gerekiyorsa ve sonra birkaç indeksi vurursanız çok daha iyi olurdu. İki kez döngü yapmanız gerekiyorsa, daha da kötüsü. Değiştirmeniz gerekiyorsa, tamamen işe yaramaz. * Yapmak * kullanmak 'ConvertAll' over' Select', downside bu şekilde yapma alışkanlığınız olduğunda özgürleşecek bir mikro optimizasyon türüdür. –

+0

Yeterince doğru, ancak kırılma değil. Dolayısıyla, daha kullanışlı bulduğunuz her şeyi kullanın. IEnumerable birçok durumda iyi, bu yüzden ToList'i Select kullanırken kullanırken anlamsız hale getirecektir.Eğer sadece Count kullanacak ve birkaç indekse isabet edecekseniz, muhtemelen sadece orijinal liste btw'den almak için daha iyi olacaktır. Yepyeni bir listenin tanıtımı, aynı zamanda testislerle de desteklenmesi anlamına geliyor. – Arcturus

1

Sen

List<string> userNames = users.ConvertAll(u => u.UserName); 
İlgili konular