Linq GroupBy和Join

时间:2014-03-09 12:55:12

标签: c# linq

我正在研究一些“解决”客户问题的机器。

这就是我的客户问题的样子:

public class ClientProblem
{
    public int ClientID { get; set; }

    public string TaskToSolve { get; set; }
}

我每天准备一份我今天必须解决的所有问题的清单。该列表看起来像这样:

List<ClientProblem> tasks = new List<ClientProblem>();

// Filling the list with task to be solved today

// list[0] = client 1 task 1
// list[1] = client 1 task 2
// ...
// list[n-1] = client 1 task n

// list[n+1] = client 2 task 1
// list[n+2] = client 2 task 2
// ...
// list[2n-1] = client 2 task 2n

// ...

我得到的问题是客户端N的问题仅在解决其他客户端的所有问题时才结束。这使得客户N挨饿。

我想混合所有问题,而不是让客户挨饿。 解决方案应如下所示:

// list[0] = client 1 task 1
// list[1] = client 2 task 1
// ...
// list[n] = client n task 1
// list[n+1] = client 1 task 2
// list[n+2] = client 2 task 2
// ...
// list[2n] = client n task 2
// ...

我想我应该使用Linq GroupBy和Join方法。 Linq可以解决这个问题吗?还有其他有效的解决方案吗?

2 个答案:

答案 0 :(得分:1)

定义以下扩展方法后

public static class SomeExtensions
{
    public static IEnumerable<T> InterleaveBy<T, S>(this IEnumerable<T> input, Func<T, S> selector)
    {
        return input
            .GroupBy(selector)
            .SelectMany(g => g.Select((x, i) => new { key = i, value = x }))
            .OrderBy(x => x.key)
            .Select(x => x.value);
    }
}

您可以将其用作

var newList = tasks.InterleaveBy(c=>c.ClientID).ToList();

如果你有列表清单那么

var newList = tasks.SelectMany(x => x).InterleaveBy(c=>c.ClientID).ToList();

答案 1 :(得分:0)

您想要的是按客户端ID对任务进行分组,然后交错组。我担心LINQ没有交错方法,但你可以创建自己的方法,例如像这样:

public static IEnumerable<T> Interleave<T>( IEnumerable<IEnumerable<T>> sequences )
{
    var enumerators = sequences.Select( s => s.GetEnumerator() ).ToArray();
    while ( true )
    {
        foreach ( var e in enumerators )
        {
            if ( e.MoveNext() )
            {
                yield return e.Current;
            }
            else
            {
                yield break;
            }
        }
    }
}

此方法假定所有序列长度相同;如果不是这种情况,你需要添加一个标志,指示枚举器是否返回了任何元素,并使循环条件依赖于它,而不是在一个序列结束时使用yield break