为了账号安全,请及时绑定邮箱和手机立即绑定

使用LINQ选择不同列的唯一值

使用LINQ选择不同列的唯一值

C#
拉莫斯之舞 2021-05-18 17:18:12
我有一个具有多列的表(例如ex的订单)。products    categories  subcategories--------------------------------------prod1       cat1        sub1prod1       cat2        sub2prod2       cat3        sub6prod1       cat1        sub1prod5       cat2        sub8prod2       cat1        sub1prod1       cat7        sub3prod8       cat2        sub2prod2       cat3        sub1现在,我可以编写三个不同的查询来获取不同的值var prod = (from p in _context.orders select p.products).ToList().Distinct();同样,我可以为他人编写。现在,我需要在单个查询中获取每一列的不同值,其结果需要像products    categories  subcategories--------------------------------------prod1       cat1        sub1prod2       cat2        sub2prod5       cat3        sub6prod8       cat7        sub8                        sub3我的唯一字段的ClassType看起来像这样public class UniqueProductFields{    public IEnumerable<string> Products { get; set; }    public IEnumerable<string> Categories { get; set; }    public IEnumerable<string> Subcategories { get; set; }}   不知道如何以有效的方式执行此操作,这样我就不必编写三种方法。该表位于数据库中(因此需要进行优化)
查看完整描述

2 回答

?
富国沪深

TA贡献1790条经验 获得超9个赞

使用Linq是绝对不变的要求吗?为什么需要在单个查询中将其返回?


建议:使用SQL。它可以在一个单一的查询做,但你不会喜欢的查询。我假设使用SQL Server(可以对其他DBMS进行不同的处理)。


WITH V AS (

   SELECT DISTINCT

      V.*

   FROM

      Orders O

      CROSS APPLY (

         VALUES (1, O.Products), (2, O.Categories), (3, O.Subcategories)

      ) V (Which, Value)

),

Nums AS (

   SELECT

      Num = Row_Number() OVER (PARTITION BY V.Which ORDER BY V.Value),

      V.Which,

      V.Value

   FROM

      V

)

SELECT

   Products = P.[1],

   Categories = P.[2],

   Subcategories = P.[3]

FROM

   Nums N

   PIVOT (Max(N.Value) FOR N.Which IN ([1], [2], [3])) P

;

看到此工作在db <> fiddle

输出:


Products  Categories  Subcategories

--------  ----------  -------------

prod1     cat1        sub1

prod2     cat2        sub2

prod5     cat3        sub3

prod8     cat7        sub6

null      null        sub8

如果您被束缚并决心使用Linq,那么我将无法为您提供查询样式的语法。我只知道C#代码样式的语法,但是这是一个刺脚。不幸的是,我认为这不会为您带来任何好处,因为我不得不使用一些非常时髦的东西来使其工作。它使用与上面的SQL查询基本相同的技术,只是,PIVOTLinq中没有等效的技术,除了自定义类之外,没有真正的自然行对象。


using System;

using System.Collections.Generic;

using System.Linq;


public class Program {

    public static void Main() {

        var data = new List<Order> {

            new Order("prod1", "cat1", "sub1"),

            new Order("prod1", "cat2", "sub2"),

            new Order("prod2", "cat3", "sub6"),

            new Order("prod1", "cat1", "sub1"),

            new Order("prod5", "cat2", "sub8"),

            new Order("prod2", "cat1", "sub1"),

            new Order("prod1", "cat7", "sub3"),

            new Order("prod8", "cat2", "sub2"),

            new Order("prod2", "cat3", "sub1")

        };

        int max = 0;

        var items = data

            .SelectMany(o => new List<KeyValuePair<int, string>> {

                new KeyValuePair<int, string>(1, o.Products),

                new KeyValuePair<int, string>(2, o.Categories),

                new KeyValuePair<int, string>(3, o.Subcategories)

            })

            .Distinct()

            .GroupBy(d => d.Key)

            .Select(g => {

                var l = g.Select(d => d.Value).ToList();

                max = Math.Max(max, l.Count);

                return l;

            })

            .ToList();

        Enumerable

            .Range(0, max)

            .Select(i => new {

                p = items[0].ItemAtOrDefault(i, null),

                c = items[1].ItemAtOrDefault(i, null),

                s = items[2].ItemAtOrDefault(i, null)

            })

            .ToList()

            .ForEach(row => Console.WriteLine($"p: {row.p}, c: {row.c}, s: {row.s}"));

    }

}


public static class ListExtensions {

    public static T ItemAtOrDefault<T>(this List<T> list, int index, T defaultValue)

        => index >= list.Count ? defaultValue : list[index];

}


public class Order {

    public Order(string products, string categories, string subcategories) {

        Products = products;

        Categories = categories;

        Subcategories = subcategories;

    }

    public string Products { get; set; }

    public string Categories { get; set; }

    public string Subcategories { get; set; }

}

我想我们可以交换一下


.Select(i => new {

   p = items[0].ItemAtOrDefault(i, null),

   c = items[1].ItemAtOrDefault(i, null),

   s = items[2].ItemAtOrDefault(i, null)

})

为了这:


.Select(i => new Order(

   items[0].ItemAtOrDefault(i, null),

   items[1].ItemAtOrDefault(i, null),

   items[2].ItemAtOrDefault(i, null)

))

然后在输出部分中使用该类的属性。


查看完整回答
反对 回复 2021-05-23
  • 2 回答
  • 0 关注
  • 183 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信