使用LINQ MVC基于两个属性对列表中的项目进行分组

时间:2018-01-18 09:29:25

标签: c# list linq

我正在进行API集成。 我有这样的模型

public class Flight
{
    public string Origin{ get; set; }
    public string Destination{ get; set; }
    public string FlightNumber{ get; set; }
    public string Provider{ get; set; }
}

这样的航班列表

 List<Flight> Flight= new List<Flight>();

让我们假设这些是数据

Flight:
{
    Segment1: { Origin= CMB , Destination=MAA , FlightNumber= 123, Provider= p}
    Segment2: { Origin= MAA, Destination= DEL, FlightNumber= 543, Provider= p }
    Segment3: { Origin= MAA, Destination= DEL, FlightNumber= 320, Provider= p}
    Segment4: { Origin= CMB, Destination= BOM, FlightNumber= 644, Provider= p}
    Segment5: { Origin= BOM, Destination= DEL, FlightNumber= 233, Provider= p}
    Segment6: { Origin= CMB, Destination= KMG, FlightNumber= 233, Provider= p}
    Segment7: { Origin= KMG, Destination= PEK, FlightNumber= 233, Provider= p}
    Segment8: { Origin= PEK, Destination= DEL, FlightNumber= 233, Provider= p}
}

SearchingOrigin =“CMB”

SearchingDestination =“DEL”

我需要将这些项目分组,如下所示

Transit_segmentList---->[0]---->[0]{ Origin= CMB , Destination=MAA , FlightNumber= 123, Provider= p}
                    |           [1]{ Origin= MAA, Destination= DEL, FlightNumber= 543, Provider= p }
                    |           [2]{ Origin= MAA, Destination= DEL, FlightNumber= 320, Provider= p}
                    |
                    --->[1]---->[0]{ Origin= CMB, Destination= BOM, FlightNumber= 644, Provider= p}
                    |           [1]{ Origin= BOM, Destination= DEL, FlightNumber= 233, Provider= p}
                    |
                    --->[2]---->[0]{ Origin= CMB, Destination= KMG, FlightNumber= 233, Provider= p}
                                [1]{ Origin= KMG, Destination= PEK, FlightNumber= 233, Provider= p}
                                [2]{ Origin= PEK, Destination= DEL, FlightNumber= 233, Provider= p}

我的主要来源是CMB,主要目的地是DEL。我想像这样分组他们

1)实际上,第1,2,3段是单次旅行的航班细节。飞机在前往 DEL 的路上停在 MAA 。段3是段2的备用段。 所以我想将这3个片段带到一个列表项( Transit_segmentList )。

2)同上面一样。飞行从CMB飞到DEL.It停在BOM。但这是一次旅行。我想把它作为第二次旅行到达 Transit_segmentList

3)段6,7,8也是同一行程的一部分。必须将它们排序为上图

2 个答案:

答案 0 :(得分:0)

使用几种扩展方法,您可以生成所有航班组合并将其过滤到所需的航班组合,然后在第一个航班上将它们组合在一起。

以下是扩展方法:

public static IEnumerable<T> AsSingleton<T>(this T first) {
    yield return first;
}

public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> elements, int k) {
    return k == 0 ? new[] { new T[0] } :
      elements.SelectMany((e, i) =>
        elements.Skip(i + 1).Combinations(k - 1).Select(c => (new[] { e }).Concat(c)));
}

然后您只需生成组合并过滤:

var ans = Enumerable.Range(1, Flights.Length)
                    .SelectMany(k => Flights.Combinations(k))
                    .Where(fs => fs.Count() == 1 || fs.Where(f1 => fs.Any(f2 => f1.Destination == f2.Origin)).Count() == fs.Count() - 1)
                    .Where(fs => fs.Any(f => f.Origin == SearchingOrigin) && fs.Any(f => f.Destination == SearchingDestination))
                    .GroupBy(fs => fs.Where(f => f.Origin == SearchingOrigin).First())
                    .Select(fsg => fsg.Key.AsSingleton().Concat(fsg.SelectMany(fs => fs.Except(fsg.Key.AsSingleton()))).ToList())
                    .ToList();

答案 1 :(得分:0)

一种选择是在细分中构建图形,并遍历所有组合/路径/行程。

在某种程度上类似于第一种方法的另一种方法是迭代细分,.Push每个细分到Stack,找到下一个目的地,递归< / em>,一旦没有更多关联的目标要评估,请确保当前段为.Pop(见下文)。

public class Segment
{
    public string Name { get; set; }
    public string Origin { get; set; }
    public string Destination { get; set; }
    public string Flight { get; set; }
}

public class Analyzer
{
    public Analyzer(IEnumerable<Segment> segments)
    {
        Segments = segments;
    }

    protected IEnumerable<Segment> Segments { get; set; }

    public IEnumerable<IEnumerable<Segment>> Process(IEnumerable<Segment> origins = null, Stack<Segment> current = null)
    {
        if (origins == null)
            origins = Segments;
        if (current == null)
            current = new Stack<Segment>();

        foreach (var origin in origins)
        {
            current.Push(origin);

            var destinations = Segments.Where(p => p.Origin == origin.Destination);
            if (destinations.Any())
            {
                foreach (var child in Process(destinations, current))
                {
                    yield return child;
                };
            }
            else
            {
                yield return current.Reverse().ToList();
            }

            current.Pop();
        }
    }
}

这将为您提供所有行程(段组)组合

var itineraries = new Analyzer(segments).Process();

itineraries

但是你提到你希望它们按初始航班分组,因为同一行程可能有很多变种,这是完全有道理的

var query = from itinerary in itineraries
            let first = itinerary.First()
            let last = itinerary.Last()
            where trip.Origin == first.Origin
                && trip.Destination == last.Destination
            group itinerary by first.Flight into groupings
            select groupings
                .SelectMany(p => p)
                .Distinct();

这应该会给你预期的结果

results

注意:当然,迭代这种方式并在进行递归时会产生成本,如果图表非常深,可能会有一些性能损失,但在讨论航段时,则越少越好:)