按属性合并列表中的元素

时间:2015-04-29 09:13:55

标签: c#

上下文

我有一个时间间隔列表。时间间隔类型为HistoMesures

每个HistoMesureDebut(开始)属性,Fin(结束)属性和Commentaires(小注释)属性定义。

我的清单是这样制作的:

  • 所有HistoMesure 独占,我的意思是他们不能相互重叠。
  • 列表按Debut排序,因此按间隔开始排序。
  • 修改:此配置中所有HistoMesure都是连续的。

问题

我想合并(在一个大间隔中转换两个小间隔)所有相邻 HistoMesure具有相同的Commentaires。目前我这样做:

//sortedHistos type is List<HistoMesure>
int i = 0;
while (i < sortedHistos.Count - 1)
{
    if (sortedHistos[i].Commentaires == sortedHistos[i + 1].Commentaires)
    {
        sortedHistos[i].Fin = sortedHistos[i + 1].Fin;
        sortedHistos.RemoveAt(i + 1);
    }
    else
    {
        ++i;
    }
}

但是我觉得它存在一种更优雅的方式,可能是LINQ。你有什么建议吗?

4 个答案:

答案 0 :(得分:3)

你的解决方案运行正常,我会保留它。

如果它不符合您的要求,请不要尝试使用LINQ。 LINQ非常适合编写查询(这是LINQ的Q),修改现有列表并不是那么好。

答案 1 :(得分:2)

此代码将产生重叠的合并间隔。即如果你有间隔A,B,C,其中A和C有相同的注释,结果将是AC,B:

var result = from h in sortedHistos
             group h by h.Commentaires into g
             select new HistoMesure {
                 Debut = g.First().Debut, // thus you have sorted entries
                 Fin = g.Last().Fin,
                 Commentaires = g.Key
             };

如果未对间隔进行排序,则可以使用MinMax

更新:没有默认的LINQ运算符允许您创建相邻的组。但你总能创造一个。这是IEnumerable<T>扩展名(我跳过参数检查):

public static IEnumerable<IGrouping<TKey, TElement>> GroupAdjacent<TKey, TElement>(
    this IEnumerable<TElement> source, Func<TElement, TKey> keySelector)
{
    using (var iterator = source.GetEnumerator())
    {
        if(!iterator.MoveNext())
        {
            yield break;
        }
        else
        {
            var comparer = Comparer<TKey>.Default;
            var group = new Grouping<TKey, TElement>(keySelector(iterator.Current));
            group.Add(iterator.Current);

            while(iterator.MoveNext())
            {
                TKey key = keySelector(iterator.Current);
                if (comparer.Compare(key, group.Key) != 0)
                {
                    yield return group;
                    group = new Grouping<TKey, TElement>(key);
                }

                group.Add(iterator.Current);                        
            }

            if (group.Any())
                yield return group;
        }
    }
}

此扩展名创建具有相同键值的相邻元素组。不幸的是,.NET中的所有IGrouping实现都是内部的,所以你需要你的:

public class Grouping<TKey, TElement> : IGrouping<TKey, TElement>
{
    private List<TElement> elements = new List<TElement>();

    public Grouping(TKey key)
    {
        Key = key;
    }

    public TKey Key { get; private set; }

    public IEnumerator<TElement> GetEnumerator()
    {
        return elements.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public void Add(TElement element)
    {
        elements.Add(element);
    }
}

现在您的代码将如下所示:

var result = sortedHistos.GroupAdjacent(h => h.Commentaries)
                         .Select(g => new HistoMesure {
                              Debut = g.Min(h => h.Debut),
                              Fin = g.Max(h => h.Fin),
                              Commentaries = g.Key
                          });

答案 2 :(得分:1)

使用Linq并从this article借用相邻值进行分组,这应该有效:

您的查询:

var filteredHistos = sortedHistos
    .GroupAdjacent(h => h.Commentaires)
    .Select(g => new HistoMesure
    {
        Debut = g.First().Debut,
        Fin = g.Last().Fin,
        Commentaires = g.Key
    });

从文章中复制,其余代码分组为:

public class GroupOfAdjacent<TSource, TKey> : IEnumerable<TSource>, IGrouping<TKey, TSource>
{
    public TKey Key { get; set; }
    private List<TSource> GroupList { get; set; }
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return ((System.Collections.Generic.IEnumerable<TSource>)this).GetEnumerator();
    }
    System.Collections.Generic.IEnumerator<TSource> System.Collections.Generic.IEnumerable<TSource>.GetEnumerator()
    {
        foreach (var s in GroupList)
            yield return s;
    }
    public GroupOfAdjacent(List<TSource> source, TKey key)
    {
        GroupList = source;
        Key = key;
    }
}
public static class LocalExtensions
{
    public static IEnumerable<IGrouping<TKey, TSource>> GroupAdjacent<TSource, TKey>(
        this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector)
    {
        TKey last = default(TKey);
        bool haveLast = false;
        List<TSource> list = new List<TSource>();
        foreach (TSource s in source)
        {
            TKey k = keySelector(s);
            if (haveLast)
            {
                if (!k.Equals(last))
                {
                    yield return new GroupOfAdjacent<TSource, TKey>(list, last);
                    list = new List<TSource>();
                    list.Add(s);
                    last = k;
                }
                else
                {
                    list.Add(s);
                    last = k;
                }
            }
            else
            {
                list.Add(s);
                last = k;
                haveLast = true;
            }
        }
        if (haveLast)
            yield return new GroupOfAdjacent<TSource, TKey>(list, last);
    }
}

答案 3 :(得分:0)

如果我理解正确,你需要这样的东西:

this.node.onaudioprocess = function(e){
      if (!recording) return;
      var buffer = [];
      for (var channel = 0; channel <1; channel++){
          buffer.push(e.inputBuffer.getChannelData(channel));
      }
      worker.postMessage({
        command: 'record',
        buffer: buffer
      });
    }