C# 将对象的最后一次出现添加到按最近添加顺序排列的列表中
我需要一个各种各样的日志,必须不时地转储内容。 我只想获取每个项目的最后一个实例,并保留该顺序 有没有比这样更好的方法?contains非常昂贵,但我对额外哈希集的内存开销也不满意C# 将对象的最后一次出现添加到按最近添加顺序排列的列表中,c#,performance,logging,C#,Performance,Logging,我需要一个各种各样的日志,必须不时地转储内容。 我只想获取每个项目的最后一个实例,并保留该顺序 有没有比这样更好的方法?contains非常昂贵,但我对额外哈希集的内存开销也不满意 public List<Int3> UnsafeDumpMostRecentUsageLast() { HashSet<Int3> _containsHelper = new HashSet<Int3>(); List<Int3> u
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;
}
public List UnsafeDumpMostRecentUsageLast(){
HashSet _containsHelper=新HashSet();
List UniqueOccurrenceSordered=新列表(uniqueConsumedCount);
对于(int i=usageLog.Length-1;i>=0;i--){
如果(_containsHelper.Add(usageLog[i]))
唯一发生排序添加(usageLog[i]);
}
UniqueOccurrenceSordered.Reverse();
返回唯一发生排序;
}
把它弄清楚。。假设我有这样一个列表:
var str = "aabbbaabbbccabccccdeddaccc";
var result = new string(str
.Reverse()
.Distinct()
.Reverse()
.ToArray()
);
aabbbabbbccabcccdedcc
我想返回一个返回大写字母的列表:
aabbbabbbccabcccdedcc
所以名单应该是:贝达克
不是:
aabbbabbbccabcccdedcc
ABCDE我不确定
Int3
类型是什么,但是如果我们假设我们谈论的是一个int(在其他情况下工作类似),并且usageLog
是一个IEnumerable
您可以执行以下操作:
public List<Int3> UnsafeDumpMostRecentUsageLast() {
return usageLog.Distinct().ToList();
}
public List UnsafeDumpMostRecentUsageLast(){
返回usageLog.Distinct().ToList();
}
添加
如果您的列表已经排序,并且您只想保留每个实例的最后一次出现(如您的注释所示):
usageLog.Reverse().Distinct().Reverse().ToList()
我不确定Int3
类型是什么,但是如果我们假设我们谈论的是一个int(在其他情况下工作类似),并且usageLog
是一个IEnumerable
,那么您可以执行以下操作:
public List<Int3> UnsafeDumpMostRecentUsageLast() {
return usageLog.Distinct().ToList();
}
public List UnsafeDumpMostRecentUsageLast(){
返回usageLog.Distinct().ToList();
}
添加
如果您的列表已经排序,并且您只想保留每个实例的最后一次出现(如您的注释所示):
usageLog.Reverse().Distinct().Reverse().ToList()代码>您可以执行以下操作:
var str = "aabbbaabbbccabccccdeddaccc";
var result = new string(str
.Reverse()
.Distinct()
.Reverse()
.ToArray()
);
您可以这样做:
var str = "aabbbaabbbccabccccdeddaccc";
var result = new string(str
.Reverse()
.Distinct()
.Reverse()
.ToArray()
);
基于哈希的查找为您提供了最佳的时间复杂度(从而提高了性能)。如果您对HashSet
类空间开销(以及扩展内部存储和重新灰化的额外成本)不满意,那么为所需的操作创建自己的哈希结构并不困难
例如,下面的算法使用大小为N
的2int
数组以更少的开销实现相同的目标。第一个名为head
的数组用于哈希表bucket链表开始索引,而next
保存bucket中下一个条目的索引,还用于标识最后一个唯一条目。不需要存储这些值,因为我们已经有了它们,而且整个映射都是按索引进行的
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;
}
基于哈希的查找为您提供了最佳的时间复杂度(从而提高了性能)。如果您对HashSet
类空间开销(以及扩展内部存储和重新灰化的额外成本)不满意,那么为所需的操作创建自己的哈希结构并不困难
例如,下面的算法使用大小为N
的2int
数组以更少的开销实现相同的目标。第一个名为head
的数组用于哈希表bucket链表开始索引,而next
保存bucket中下一个条目的索引,还用于标识最后一个唯一条目。不需要存储这些值,因为我们已经有了它们,而且整个映射都是按索引进行的
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;
}
那会给我错误的顺序。我用一个例子更新了我的OP。。。将“返回usageLog.Reverse().Distinct().Reverse().ToList();”做我想做的吗?@user3488765更新了answerWow,这被认为比原始实现性能更好-为Distiinct
+设置了额外的缓冲区,用于反向
+来自ToList
的额外列表。真可笑。最好删除performance
标记。@IvanStoev我删除了接受答案。在Rob发布了与SteelSoul相同的帖子,我看到了他的名声之后,我没有对答案做更多的研究,因为我认为如果他们费心留下回复,他们会知道得更好。你知道比我原来的方法更好的方法吗?事实上没有:)我认为这是最好的。我看到的唯一潜在的改进是用一些定制的轻量级等价物替换哈希集
,主要是为了避免重新分配,因为没有办法预先指定哈希集的容量。这会给我错误的顺序。我用一个例子更新了我的OP。。。将“返回usageLog.Reverse().Distinct().Reverse().ToList();”做我想做的吗?@user3488765更新了answerWow,这被认为比原始实现性能更好-为Distiinct
+设置了额外的缓冲区,用于反向
+来自ToList
的额外列表。真可笑。最好删除performance
标记。@IvanStoev我删除了接受答案。在Rob发布了与SteelSoul相同的帖子,我看到了他的名声之后,我没有对答案做更多的研究,因为我认为如果他们费心留下回复,他们会知道得更好。你知道比我原来的方法更好的方法吗?事实上没有:)我认为这是最好的。我所看到的唯一潜在改进是用一些定制的轻量级等价物替换哈希集
,主要是为了避免重新分配,因为没有办法预先指定哈希集的容量。List.contains太贵了,但我对额外哈希集的内存开销也不满意。然后你可以考虑,例如从