2017-10-10 71 views
-2

我有兩個以下值列表。將兩個列表合併在一起,並且如果它存在於另一個值上,則取一個值

PirateShipList1

Date  | PirateShipName  | CrewMembers 
--------------------------------------------- 
1/1/1800 | Cindy    | 5 
1/2/1800 | TheIvan   | 20 
1/3/1800 | TheTerrible  | 10 

而且PirateShipList2

Date  | PirateShipName  | CrewMembers 
--------------------------------------------- 
1/1/1800 | Cindy    | 0 
1/2/1800 | Cindy    | 0 
1/3/1800 | Cindy    | 0 
1/1/1800 | TheIvan   | 0 
1/2/1800 | TheIvan   | 0 
1/3/1800 | TheIvan   | 0 
1/1/1800 | TheTerrible  | 0 
1/2/1800 | TheTerrible  | 0 
1/3/1800 | TheTerrible  | 0 

我想這兩個列表合併的日期和PirateShipName這樣,如果它是存在於列表1,我把它的機組人員價值,否則我把名單2 CrewMembers值。

因此最終列表看起來像。

Date  | PirateShipName  | CrewMembers 
--------------------------------------------- 
1/1/1800 | Cindy    | 5 
1/2/1800 | Cindy    | 0 
1/3/1800 | Cindy    | 0 
1/1/1800 | TheIvan   | 0 
1/2/1800 | TheIvan   | 20 
1/3/1800 | TheIvan   | 0 
1/1/1800 | TheTerrible  | 0 
1/2/1800 | TheTerrible  | 0 
1/3/1800 | TheTerrible  | 10 

我發現我可以通過以下

List<PirateLedgers> Final = PirateShipList2.Union(PirateShipList1) 
.GroupBy(x => new { x.Date, x.PirateShipName }) 
.Select(x => new PirateLedgers 
{  
Date = x.Key.Date, 
PirateShipName = x.Key.PirateShipName, 
CrewMembers = x.Sum(l => l.CrewMembers)        
}).ToList<PirateLedgers>(); 

做到這一點hackily但我懷疑,有一個實際參加這樣做的更聰明,更好的辦法。先謝謝你了!

+0

https://codereview.stackexchange.com –

+0

您的查詢和它的描述是完全不同的。描述是「合併列表,優先於列表1中的值到列表2」,並且查詢是「合併列表並對值進行求和」。它們只是相同的,因爲在你的特例中,列表2中的所有值都是零。如果列表2中的值不是零,會發生什麼? –

+1

如何修改PirateShipList2 **的一個**克隆,然後在PirateShipList1 **上運行一個** foreach循環,以及如果找到該特定日期和PirateShipName的任何記錄**替換CrewMembers ** ...我不知道多少會更好,因爲會惹你的查詢....只是我的想法:) –

回答

0

這個查詢應該這樣做:

var query = 
    from s2 in PirateShipList2 
    join s1 in PirateShipList1 on s2.PirateShipName equals s1.PirateShipName 
    select new 
    { 
     s2.Date, 
     s2.PirateShipName, 
     CrewMember = s1.Date == s2.Date ? s1.CrewMember : s2.CrewMember 
    }; 

在方法的語法:

PirateShipList2 
    .Join(PirateShipList1, 
     x => x.PirateShipName, x=> x.PirateShipName, 
     (s2, s1) => new 
     { 
      s2.Date, 
      s2.PirateShipName, 
      CrewMember = s1.Date == s2.Date ? s1.CrewMember : s2.CrewMember 
     }); 

編輯:由於@spender指出,上述方案爲每組匹配名稱產生笛卡爾連接。所以,這裏是另一種解決方案:

PirateShipList2 
    .Select(s2 => new 
    { 
     s2, 
     s1 = PirateShipList1.FirstOrDefault(s1 => 
      s1.PirateShipName == s2.PirateShipName && 
      s1.Date == s2.Date) 
    }) 
    .Select(x => new 
    { 
     x.s2.Date, 
     x.s2.PirateShipName, 
     CrewMember = x.s1 != null ? x.s1.CrewMember : x.s2.CrewMember 
    }) 
+2

爲每組匹配名稱生成笛卡爾連接。在list1中有兩艘船「A」,在list2中有三艘船「A」,你會在名稱匹配的地方生成6個結果。 – spender

+1

事實上,我認爲第一套將是獨一無二的,我可能不應該。我會解決這個問題... – Xiaoy312

+1

@spender我修復了它。 – Xiaoy312

0

給一個嘗試

PirateShipList1.Union(PirateShipList2).GroupBy(x => new { x.Date, x.Name }, (key, value) => value.OrderByDescending(x => x.Number).First()); 
0

考慮加入這個共同Distinct超載

public static IEnumerable<TSource> Distinct<TSource, TKey> 
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) 
{ 
    HashSet<TKey> seen = new HashSet<TKey>(); 
    foreach (TSource element in source) 
    { 
     if (seen.Add(keySelector(element))) 
     { 
      yield return element; 
     } 
    } 
} 

,然後用它因而

var final = PirateShipList1.Concat(PirateShipList2).Distinct(x => x.PirateShipName); 

小心,這種方法只有「內存」工程(即IEnumerable,而不是IQueryable級別)。

這種方法的好處是它保留了順序,只做必要的計算 - 它丟棄了任何它不需要的東西List2。它也非常具有說明性和可讀性(這是LINQ的一個巨大優勢)。

相關問題