获取列表中给定字符串项的下一项<>

Get next item of a given string item in a List<>

提问人:Lifewithsun 提问时间:10/18/2023 更新时间:10/18/2023 访问量:67

问:

我有一个数据列表,我想通过查找字符串值匹配来循环访问该列表,该列表如下所示:

enter image description here

我希望输出为:

enter image description here

为了实现这一点,我尝试使用 linq,但我没有得到所需的输出。

List<WorkItemStateTime> workItems = new List<WorkItemStateTime>();               

int totalCount = 0; int currentId = 1;
string currentState;

totalCount = revisionData.Count;
do
{
    WorkItemStateTime workItemStateTime = new WorkItemStateTime();
    var currRow = revisionData.Where(x => x.rev == currentId).FirstOrDefault();                    
    currentState = currRow.fields.SystemState;
    workItemStateTime.State = currentState;
    workItemStateTime.StartTime = currRow.fields.SystemChangedDate;

    var nextRow = revisionData.SkipWhile(x => x.fields.SystemState != currentState).Skip(1).FirstOrDefault();
    currentId = nextRow.rev;
    workItemStateTime.EndTime = nextRow.fields.SystemChangedDate;
    workItems.Add(workItemStateTime);

} while ((currentId - 1) < totalCount);
C# 列表 LINQ

评论

0赞 SHUBHAM SHEDGE 10/18/2023
若要实现所需的输出,即要对具有相同状态的连续行进行分组并计算开始日期和结束日期,可以更有条理地使用 LINQ。
0赞 Prasad Telkikar 10/18/2023
@SHUBHAMSHEDGE,我不认为 group by 会在这里工作。.因为在这里,状态序列很重要。请看第 7 排。

答:

2赞 SomeBody 10/18/2023 #1

如果需要列表项之间的交互,则 LINQ 非常糟糕。在您的情况下,您需要具有不同状态的下一个项目的开始时间。我建议你使用经典循环:

for(int i = 0; i < data.Count; i++)
        {
            for(int j = i+1; j < data.Count; j++)
            {
                if(data[i].State != data[j].State)
                {
                    result.Add(new Item { State = data[i].State, Start = data[i].Start, End = data[j].Start });
                    i = j;
                    continue;
                }
            }
            result.Add(new Item { State = data[i].State, Start = data[i].Start, End = DateTime.Now });
        }

输出循环遍历您的完整输入。内部循环一直运行,直到找到具有不同状态的项。如果找到此项,我们将一个新项添加到结果列表中,其中包含第一个项的开始时间和在内循环中找到的项的结束时间。然后,通过将外部循环的索引设置为内部循环的索引来跳过所有这些具有相同状态的项。如果没有找到项目,我们显然在列表的末尾,我们将一个项目添加到结果列表中,结束时间是当前时间。

在线演示:https://dotnetfiddle.net/jfgvuj

1赞 Oliver 10/18/2023 #2

在 Reactive Extensions 中存在 DistinctUntilChanged 方法。通过对 IEnumerable 实现类似的方法,可以实现相同的目标:

public static class MyExtensions
{
    public static IEnumerable<T> DistinctUntilChangedBy<T, TKey>(
        this IEnumerable<T> source,
        Func<T, TKey> keySelector,
        IEqualityComparer<TKey> keyComparer = null)
    {
        keyComparer ??= EqualityComparer<TKey>.Default;

        var last = default(TKey);
        var haveLast = false;

        foreach (var item in source)
        {
            var current = keySelector(item);
            if (!haveLast || !keyComparer.Equals(last, current))
            {
                haveLast = true;
                last = current;
                yield return item;
            }
        }
    }
}

若要使用此方法,可以查看以下示例:

    var items = new[] 
    {
        new MyItem { Value = 1, Name = "A" },
        new MyItem { Value = 2, Name = "B" },
        new MyItem { Value = 2, Name = "C" },
        new MyItem { Value = 3, Name = "D" },
        new MyItem { Value = 2, Name = "E" },
        new MyItem { Value = 1, Name = "F" },
    };

    var distinctItems = items.DistinctUntilChangedBy(item => item.Value);

    foreach (var item in distinctItems)
    {
        Console.WriteLine($"{item.Value} {item.Name}");
    }

输出将是:

1 A
2 B
3 D
2 E
1 F