将最后一次出现的对象添加到按最近添加顺序排列的列表中

时间:2016-11-20 21:51:49

标签: c# performance logging

我需要一种各种记录器,并且必须不时地转储内容。 我想只获取每个项目的最后一个实例并保留该顺序。

有没有比这更好的方法呢? List.contains是昂贵的,但我不满意额外的hashset的内存开销。

 public List<Int3> UnsafeDumpMostRecentUsageLast() {

        HashSet<Int3> _containsHelper = new HashSet<Int3>();
        List<Int3> uniqueOccurencesOrdered = new List<Int3>(uniqueConsumedCount);

        for (int i = usageLog.Length-1;i >= 0; i--) {

            if (_containsHelper.Add(usageLog[i])) 
                uniqueOccurencesOrdered.Add(usageLog[i]);

        }
        uniqueOccurencesOrdered.Reverse();
        return uniqueOccurencesOrdered;
    }

要清除它..说我有这样的清单:

aabbbaabbbccabccccdeddaccc

我想返回一个返回大写字母的列表:

aabbbaabbbccaBccccdEdDAccC

所以列表将是:BEDAC

加: AaBbbaabbbCcabccccDEddaccc

ABCDE

3 个答案:

答案 0 :(得分:1)

我不确定Int3类型是什么,但如果我们假设我们正在讨论int(在其他情况下工作方式类似)而usageLogIEnumerable则可以执行以下内容:

public List<Int3> UnsafeDumpMostRecentUsageLast() {          
    return usageLog.Distinct().ToList();
}

<强>加成

如果您的列表已经排序,并且您只想保留每个实例的最后一次出现(如您的评论所示):

usageLog.Reverse().Distinct().Reverse().ToList();

答案 1 :(得分:1)

您可以这样做:

var str = "aabbbaabbbccabccccdeddaccc";
var result = new string(str
    .Reverse()
    .Distinct()
    .Reverse()
    .ToArray()
);

答案 2 :(得分:0)

基于哈希的查找为您提供最佳的时间复杂度(因此性能)。如果您对HashSet类空间开销(以及扩展内部存储和重新散列的额外成本)不满意,那么创建特定于所需操作的哈希结构并不困难。

例如,以下算法使用大小为int的2 N个数组来实现相同的目标,而且开销更少。名为head的第一个数组用于散列表存储桶链接列表开始索引,而next包含存储桶中下一个条目的索引,并且还用于标识最后的唯一条目。不需要存储值,因为我们已经拥有它们,整个映射是索引。

static List<T> UnsafeDumpMostRecentUsageLast<T>(IReadOnlyList<T> source, IEqualityComparer<T> comparer = null)
{
    var head = new int[source.Count];
    var next = new int[source.Count];
    int count = 0;
    if (comparer == null) comparer = EqualityComparer<T>.Default;
    for (int i = 0; i < source.Count; i++)
    {
        var item = source[i];
        // Check for duplicate
        int bucket = (comparer.GetHashCode(item) & int.MaxValue) % head.Length;
        int prev = -1, last = head[bucket] - 1;
        while (last >= 0 && !comparer.Equals(source[last], item))
            last = next[prev = last];
        if (last >= 0)
        {
            // Found, replace it in the hash chain (we need only the last) 
            next[i] = next[last];
            if (prev >= 0)
                next[prev] = i;
            else
                head[bucket] = i + 1;
            // Use int.MinValue (value < -1) to mark the duplicate entry as not being last
            next[last] = int.MinValue;
        }
        else
        {
            next[i] = head[bucket];
            head[bucket] = i + 1;
            count++;
        }
    }
    var result = new List<T>(count);
    for (int i = 0; i < next.Length; i++)
    {
        if (next[i] < -1) continue;
        result.Add(source[i]);
        if (result.Count == count) break;
    }
    return result;
}

以下是您的用法:

public List<Int3> UnsafeDumpMostRecentUsageLast()
{
    return UnsafeDumpMostRecentUsageLast(usageLog);
}

和测试:

var source = "aabbbaabbbccabccccdeddaccc".ToCharArray();
var result = UnsafeDumpMostRecentUsageLast(source);
Console.WriteLine(string.Concat(result));
// output: bedac
相关问题