none
【請益】如何透過 LINQ 投影泛型集合的類別中不同屬性合併至單一集合中? RRS feed

  • 問題

  •   不好意思打擾了,請問如何透過 LINQ 投影泛型集合的類別中不同屬性合併至單一集合中?目前的做法是透過 IEnumerable<TSource> Union<TSource> 結合多個 IEnumerable<TResult> Select<TSource, TResult> 來達成,像是下列的程式碼所示,不知道有無更佳的作法?如果有更多的屬性需要合併至集合中的話,目前只想到繼續的 Union 和 Select 而已,感覺這樣好像有點壞味道……。非常感謝!


    ※ 演示程式碼:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    public class Program
    {
    	public static void Main()
    	{
    		IEnumerable<Item> items = new List<Item>
    		{
    			new Item { Name = "Item1", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid() },
    			new Item { Name = "Item2", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid() },
    			new Item { Name = "Item3", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid() }
    		};
    	
    		IEnumerable<Guid> usersId = items.Select(x => x.CreatedUserId).Union(items.Select(x => x.ModifiedUserId));
    		usersId.Dump();
    	}
    	
    	public class Item
    	{
    		public String Name { get; set; }
    		public Guid CreatedUserId { get; set; }
    		public Guid ModifiedUserId { get; set; }
    	}
    }
    

    ※ 執行結果:

    Dumping object(System.Linq.<UnionIterator>d__88`1[Guid])
    [
    	253b93f1-770b-4843-bc0d-460a428d6115
    	,
    	9d0bd210-062e-495f-9d60-3465bbb2b575
    	,
    	715cb8df-6325-441b-8879-2e6d48a14bd3
    	,
    	b9344566-787c-40c1-8fd8-f1d35d1dacca
    	,
    	476588e9-e4f6-46c8-9b5b-494818b7821e
    	,
    	0e5a7d8a-96ac-4d5c-ae44-3bfe8e6cc816
    ]
    

    ※ 線上演示程式碼:https://dotnetfiddle.net/I96imA

    • 已編輯 Zhi-Wei 2015年10月3日 下午 07:01
    2015年10月3日 下午 06:20

解答

  • IEnumerable<Item> items = new List<Item>()
    {
    	new Item { Name = "Item1", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid() },
    	new Item { Name = "Item2", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid() },
    	new Item { Name = "Item3", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid() }
    };
    
    List<Guid> usersId = new List<Guid>();
    IEnumerable<PropertyInfo> guidProperties = typeof(Item).GetProperties().Where(p => p.PropertyType == typeof(Guid));
    foreach (PropertyInfo p in guidProperties)
    {
        foreach (Item i in items)
        {
            usersId.Add((Guid)p.GetValue(i));
        }
    }
    你可能是想問反射吧
    • 已標示為解答 Zhi-Wei 2015年10月5日 下午 03:22
    2015年10月5日 上午 02:14
  • Hi,

    如果用 Select + SelectMany 呢?

    public class Program
    {
    	public static void Main()
    	{
    		IEnumerable<Item> items = new List<Item>
    		{
    			new Item { Name = "Item1", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid(), AuditedUserId = Guid.NewGuid()},
    			new Item { Name = "Item2", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid(), AuditedUserId = Guid.NewGuid() },
    			new Item { Name = "Item3", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid(), AuditedUserId = Guid.NewGuid() }
    		};
    	
    		IEnumerable<Guid> usersId = items.Select(x => x.CreatedUserId).Union(items.Select(x => x.ModifiedUserId)).Union(items.Select(x => x.AuditedUserId));
    		usersId.Dump();
    		IEnumerable<Guid> usersId2 = items.Select(x=> new List<Guid>(){x.CreatedUserId, x.ModifiedUserId, x.AuditedUserId})
    								.SelectMany(item=>item).Distinct();
    		usersId2.Dump();
    	}
    	
    	public class Item
    	{
    		public String Name { get; set; }
    		public Guid CreatedUserId { get; set; }
    		public Guid ModifiedUserId { get; set; }
    		public Guid AuditedUserId {get; set;}
    	}
    }


    亂馬客blog: http://www.dotblogs.com.tw/rainmaker/

    • 已標示為解答 Zhi-Wei 2015年10月5日 下午 03:23
    2015年10月5日 上午 02:44

所有回覆

  • 除了Union以外就是用Concat
    • 已提議為解答 亂馬客 2015年10月4日 上午 10:56
    2015年10月4日 上午 08:20
  •   非常感謝 this 大大抽空回覆,真的非常抱歉,自己覺得可能在問題的敘述上不夠清楚;如果在問題中演示程式碼的 Item 類別再增加一個屬性,如:public Guid AuditedUserId { get; set; },那麼也需要加入至 usersId 集合中,在 LINQ 查詢投影的程式碼再加上 Union 或 Concat (看需求是否要保留重複的值)中 Select 出 AuditedUserId,如下列程式碼所示(假設需求不保留重複的值故使用 Union),如果再增加第四、第五或更多個需要加入至 usersId 集合中的屬性,因為新手的自己目前想到就是只能再串接下去,故想請益各位大大是否有更好的做法來達成目的,非常感謝!


    IEnumerable<Guid> usersId =
       items.Select(x => x.CreatedUserId)
       .Union(items.Select(x => x.ModifiedUserId))
       .Union(items.Select(x => x.AuditedUserId));
    
    2015年10月4日 下午 03:28
  • 不確定這是不是你想問的問題,如果你是要依據Select的結果產生一個新類別,你可以這樣寫

    var usersId = items.Select(x => new{x.CreatedUserId, x.ModifiedUserId});

    可以依據你選擇的屬性產生一個新類別,該類別是AnonymousType,所以要使用var宣告。如果要使用.NET Fiddle的Dump(),則需要先宣告好你產生物件的類別。若不想預先宣告類別只是想看到程式運作的結果,直接使用WriteLine就可以看到了。

    var usersId = items.Select(x => new{x.CreatedUserId, x.ModifiedUserId});
    foreach(var obj in usersId)
    	Console.WriteLine(obj.CreatedUserId);

    或是直接宣告新類別

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    public class Program
    {
    	public static void Main()
    	{
    		
    		IEnumerable<Item> items = new List<Item>
    		{
    			new Item { Name = "Item1", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid() },
    			new Item { Name = "Item2", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid() },
    			new Item { Name = "Item3", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid() }
    		};
    	
    		IEnumerable<TargetItem> usersId = items.Select(x => new TargetItem(){CreatedUserId = x.CreatedUserId, ModifiedUserId = x.ModifiedUserId});
    		usersId.Dump();		
    		
    	}
    	
    	public class TargetItem
    	{
    		public Guid CreatedUserId { get; set; }
    		public Guid ModifiedUserId { get; set; }
    	}
    	
    	public class Item
    	{
    		public String Name { get; set; }
    		public Guid CreatedUserId { get; set; }
    		public Guid ModifiedUserId { get; set; }
    	}
    	
    	
    }


    • 已編輯 Jerry C.C 2015年10月4日 下午 11:23
    2015年10月4日 下午 11:16
  • IEnumerable<Item> items = new List<Item>()
    {
    	new Item { Name = "Item1", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid() },
    	new Item { Name = "Item2", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid() },
    	new Item { Name = "Item3", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid() }
    };
    
    List<Guid> usersId = new List<Guid>();
    IEnumerable<PropertyInfo> guidProperties = typeof(Item).GetProperties().Where(p => p.PropertyType == typeof(Guid));
    foreach (PropertyInfo p in guidProperties)
    {
        foreach (Item i in items)
        {
            usersId.Add((Guid)p.GetValue(i));
        }
    }
    你可能是想問反射吧
    • 已標示為解答 Zhi-Wei 2015年10月5日 下午 03:22
    2015年10月5日 上午 02:14
  • Hi,

    如果用 Select + SelectMany 呢?

    public class Program
    {
    	public static void Main()
    	{
    		IEnumerable<Item> items = new List<Item>
    		{
    			new Item { Name = "Item1", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid(), AuditedUserId = Guid.NewGuid()},
    			new Item { Name = "Item2", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid(), AuditedUserId = Guid.NewGuid() },
    			new Item { Name = "Item3", CreatedUserId = Guid.NewGuid(), ModifiedUserId = Guid.NewGuid(), AuditedUserId = Guid.NewGuid() }
    		};
    	
    		IEnumerable<Guid> usersId = items.Select(x => x.CreatedUserId).Union(items.Select(x => x.ModifiedUserId)).Union(items.Select(x => x.AuditedUserId));
    		usersId.Dump();
    		IEnumerable<Guid> usersId2 = items.Select(x=> new List<Guid>(){x.CreatedUserId, x.ModifiedUserId, x.AuditedUserId})
    								.SelectMany(item=>item).Distinct();
    		usersId2.Dump();
    	}
    	
    	public class Item
    	{
    		public String Name { get; set; }
    		public Guid CreatedUserId { get; set; }
    		public Guid ModifiedUserId { get; set; }
    		public Guid AuditedUserId {get; set;}
    	}
    }


    亂馬客blog: http://www.dotblogs.com.tw/rainmaker/

    • 已標示為解答 Zhi-Wei 2015年10月5日 下午 03:23
    2015年10月5日 上午 02:44
  •   哇!非常感謝各位大大抽空賜教,真的非常興奮學到不少技巧,像是解開謎題般的高興!自己也是剛接觸反射,完全沒有想到也可以利用反射來達成;SelectMany 也是達成目的好方法,對於 SelectMany 不熟悉的自己還要多加練習才行。

      匿名型別 和 Concat 也都是個方便的好東西,真的很對不起自己沒能清楚表達最終想要取得 IEnumerable<Guid> 集合的問題核心,會好好反省自己問題的表達方式,盡力不要浪費各位大大的時間來解謎我的問題核心是什麼……,也煩請各位大大見諒。

      但是,這個問題如果還有其他方法的話,希望大大們能夠再賜教,同一個問題中向各位大大學習到不同的解法與技巧,真的是令人興奮啊!非常感謝!

    • 已編輯 Zhi-Wei 2015年10月5日 下午 03:27
    2015年10月5日 下午 03:25