2012-08-29 87 views
3

我有一個集合。我想選擇匹配2個條件的值。根據2條件選擇使用linq

var a; 
var b; 
foreach(SomeObject so in collection) 
{ 
    if(so.Value == something) 
    { 
     a = so; 
     // break if b is not null. 
    } 
    else if(so.Value == somethingElse) 
    { 
     b = so; 
     // break if a is not null 
    } 
} 

是否有可能使用linq迭代集合只做一次?如果我們能夠使用這個事實,那麼只有一種東西的價值和一種東西的價值。

+1

你能發表你寫的代碼嗎? – TheEvilPenguin

+0

我現在沒有代碼,但是我已經用我想要做的事更新了這個問題。 – Sam

+0

你爲什麼要這樣做?在上面的示例代碼中,'a'和'b'的值將被設置爲最後一個對象以符合它們的標準。這可以嗎? –

回答

2

你需要的東西是這樣的:

var a = collection.OfType<YourCollectionElementType>().FirstOrDefault(i=>i.Equals(something)); 
var b = collection.OfType<YourCollectionElementType>().FirstOrDefault(i=>i.Equals(somethingelse)); 

您的集合應實現IEnumerable至少要能夠使用這個代碼。 這取決於你的收藏類型是什麼。如果它實現了通用IEnumerable<T>,說這是List<YourCollectionElementType>或再數組YourCollectionElementType[]你不需要使用OfType<T>,即

var a = collection.FirstOrDefault(i=>i.Equals(something)); 
var b = collection.FirstOrDefault(i=>i.Equals(somethingelse)); 

如果集合不包含該值,a和/或b將獲得null值。

其實你可以在MSDN中閱讀所有這些東西。 LINQ是不是很難學,如果你嘗試 例如:

  1. Enumerable.FirstOrDefault Method (IEnumerable)

  2. Enumerable.OfType Method

編輯

在您的評論你說那它確信只有一個值目前。你需要兩個單獨的變量是非常重要的嗎?你可以得到的現值,就像這樣:

object thevalue = collection.FirstOrDefault(i => i == something || i == somethingelse); 

編輯

事實上,我會離開你的循環,因爲它是唯一已增加這樣一行:

SomeObject a; 
SomeObject b; 
foreach(SomeObject so in collection) 
{ 
    if(so.Value == something) 
     a = so; 
    else if(so.Value == somethingElse) 
     b = so; 
    if(a!=null && b!=null) 
     break; 
} 

並且如果僅預期其中一個值,則

SomeObject a; 
SomeObject b; 
foreach(SomeObject so in collection) 
{ 
    if(so.Value == something) 
    { 
     a = so; 
     break; 
    } 
    else if(so.Value == somethingElse) 
    { 
     b = so; 
     break; 
    } 
} 
+0

我的問題是 - 你可以在1條語句中這樣做,即只迭代一次該集合? – Sam

+0

每個東西和東西只有一個值Else – Sam

+0

我更新了僞代碼。 – Sam

0

當然可以,但我不會推薦它。現在你已經擁有了你的循環,這將是更清潔的。

如果你真的想知道怎麼了,你可以這樣做:

class SomeObject 
{ 
    public string Value { get; set; } 
} 
var items = new[] 
{ 
    new SomeObject { Value = "foo" }, 
    new SomeObject { Value = "bar" }, 
    new SomeObject { Value = "baz" }, 
}; 

var something = "foo"; 
var somethingElse = "baz"; 
var result = items.Aggregate(
    Tuple.Create(default(SomeObject), default(SomeObject)), 
    (acc, item) => Tuple.Create(
     item.Value == something  ? item : acc.Item1, 
     item.Value == somethingElse ? item : acc.Item2 
    ) 
); 
// result.Item1 <- a == new SomeObject { Value = "foo" } 
// result.Item2 <- b == new SomeObject { Value = "baz" } 
2
var relevant = 
    from so in l where so.Value == something || so.Value == somethingElse 
    group so by so.Value == something into grp 
    select new {ForA = grp.Key, SO = grp.First()}; 
foreach(var bit in relevant) 
    if(bit.ForA) 
    a = bit.SO; 
    else 
    b = bit.SO; 

它可能獲得你對某些來源的東西,因爲只有兩個項目被檢索到,雖然如果針對內存中的集合,我會保留所有內容,但要添加一個catch,以便一旦設置了ab,就停止了循環,而不是不必要地檢查集合。

1

你可以這樣做:

collection 
    .Select(x => x.Value == something 
     ?() => a = x 
     : (x.Value == somethingElse 
      ?() => b = x 
      : (Action)null)) 
    .Where(x => x != null) 
    .ToArray() 
    .ForEach(x => x()); 

我測試此代碼和它的工作一種享受。

如果集合了一個數據庫,然後某處,我建議這樣的:

collection 
    .Where(x => x.Value == something || x.Value == somethingElse) 
    .ToArray() 
    .Select(x => x.Value == something 
     ?() => a = x 
     : (x.Value == somethingElse 
      ?() => b = x 
      : (Action)null)) 
    .Where(x => x != null) 
    .ToArray() 
    .ForEach(x => x()); 
+2

我們不知道沒有100,000個不匹配的項目。 –

+0

這不是三重否定的。沒有10萬件不符合我們所知的東西。抓取100,000個物品,大部分是空的,在我們找到匹配後繼續這樣做,然後創建一個數組,當然會成爲一個問題。 –

+0

@JonHanna - 爲什麼它是一個問題?我剛剛創建了一個1,000,000個對象的列表,其中將近4000個對象相匹配,只需要52毫秒。 – Enigmativity

2

該解決方案將列表範圍縮小到兩個元素,然後從那裏去。使用Take(2),因此僅在找到兩個值之前才搜索集合。

var matches = collection.Where(x => x.Value == something || x.Value == somethingElse) 
         .Take(2) 
         .ToList(); 
var a = matches.Single(x => x.Value == something); 
var b = matches.Single(x => x.Value == somethingElse); 
0

不知道如果我理解你的問題,但假設SomethingSomethingElse是值類型和運行時間之前已知的,你可以在一個聲明中做如下圖所示。

 var FindItems = new[] 
     { 
      new SomeObject { Value = "SomethingElse" } 
     }; 

     var CollectionItems = new[] 
     { 
      new SomeObject { Value = "Something" }, 
      new SomeObject { Value = "SomethingElse" } 
     }; 

     var qSomeObject = CollectionItems 
          .Where(c => FindItems.Any(x => c.Value == x.Value));