从列表中删除重复项同时保留最新的 C#
Removing Duplicates From a list while keeping the most recent C#
所以我有几个标签类型的列表。标签有几个属性:.Epc、.AntennaPortNumber 和 .LastTimeSeen。我想从主列表中取出所有标签,并将它们分类为 5 个较小的列表,但每个 .Epc 只保留一份副本,并且它必须是最新的 .LastTimeSeen。我什至不确定从哪里开始。我在想我一定需要对嵌套几次的 .GroupBy 做些什么?现在代码分为两个主要部分:我将新标签添加到它们所属的列表中,以及我删除一个 500 毫秒内未出现的标签。我试图用 .Contains 防止将重复的标签添加到 5 个子列表中,但是因为它们具有不同的 LastTimeSeen 属性,所以没有达到预期的效果。
感谢任何人可能提供的任何指导!
List<Tag> tags = new List<Tag>();
List<Tag> listMed1 = new List<Tag>();
List<Tag> listMed2 = new List<Tag>();
List<Tag> listMed3 = new List<Tag>();
List<Tag> listMed4 = new List<Tag>();
List<Tag> listMed5 = new List<Tag>();
void OnTagsReported(ImpinjReader sender, TagReport report)
{
// This event handler is called asynchronously
// when tag reports are available.
// Loop through each tag in the report
// and print the data.
//List<Tag> tags = new List<Tag>();
foreach (Tag tag in report)
{
ushort AntennaNum = tag.AntennaPortNumber;
Impinj.OctaneSdk.TagData first = tag.Epc;
string epcCheck = first.ToString().ToUpper();
Impinj.OctaneSdk.ImpinjTimestamp tim = tag.LastSeenTime;
if (epcCheck.IndexOf("A") != -1)
{
if (listMed1.Contains(tag) == false)
{
listMed1.Add(tag);
System. Diagnostics.Debug.WriteLine(epcCheck);
System.Diagnostics.Debug.WriteLine(tim);
}
}
else if (epcCheck.IndexOf("B") != -1)
{
if (listMed2.Contains(tag) == false)
{
listMed2.Add(tag);
}
}
else if (epcCheck.IndexOf("C") != -1)
{
if (listMed3.Contains(tag) == false)
{
listMed3.Add(tag);
}
}
else if (epcCheck.IndexOf("D") != -1)
{
if (listMed1.Contains(tag) == false)
{
listMed4.Add(tag);
}
}
else if (epcCheck.IndexOf("E") != -1)
{
if (listMed5.Contains(tag) == false)
{
listMed5.Add(tag);
}
}
int Med1num = listMed1.Count();
int Med2num = listMed2.Count();
int Med3num = listMed3.Count();
int Med4num = listMed4.Count();
int Med5num = listMed5.Count();
for (int loopr = 0; loopr < Med1num; loopr++)
{
Impinj.OctaneSdk.ImpinjTimestamp second = listMed1[loopr].LastSeenTime;
string milisecondsUTC = second.ToString();
long lastseen = Convert.ToInt64(milisecondsUTC);
TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
long secondsSinceEpoch = (long)t.TotalMilliseconds;
if (secondsSinceEpoch - lastseen > 500 )
{
listMed1.RemoveAt(loopr);
loopr = -1;
}
}
for (int loopr = 0; loopr < Med2num; loopr++)
{
Impinj.OctaneSdk.ImpinjTimestamp second = listMed2[loopr].LastSeenTime;
string milisecondsUTC = second.ToString();
long lastseen = Convert.ToInt64(milisecondsUTC);
TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
long secondsSinceEpoch = (long)t.TotalMilliseconds;
if (secondsSinceEpoch - lastseen > 500)
{
listMed2.RemoveAt(loopr);
loopr = -1;
}
}
for (int loopr = 0; loopr < Med3num; loopr++)
{
Impinj.OctaneSdk.ImpinjTimestamp second = listMed3[loopr].LastSeenTime;
string milisecondsUTC = second.ToString();
long lastseen = Convert.ToInt64(milisecondsUTC);
TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
long secondsSinceEpoch = (long)t.TotalMilliseconds;
if (secondsSinceEpoch - lastseen > 500)
{
listMed3.RemoveAt(loopr);
loopr = -1;
}
}
for (int loopr = 0; loopr < Med4num; loopr++)
{
Impinj.OctaneSdk.ImpinjTimestamp second = listMed4[loopr].LastSeenTime;
string milisecondsUTC = second.ToString();
long lastseen = Convert.ToInt64(milisecondsUTC);
TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
long secondsSinceEpoch = (long)t.TotalMilliseconds;
if (secondsSinceEpoch - lastseen > 500)
{
listMed4.RemoveAt(loopr);
loopr = -1;
}
}
for (int loopr = 0; loopr < Med5num; loopr++)
{
Impinj.OctaneSdk.ImpinjTimestamp second = listMed5[loopr].LastSeenTime;
string milisecondsUTC = second.ToString();
long lastseen = Convert.ToInt64(milisecondsUTC);
TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
long secondsSinceEpoch = (long)t.TotalMilliseconds;
if (secondsSinceEpoch - lastseen > 500)
{
listMed5.RemoveAt(loopr);
loopr = -1;
}
}
Med1num = listMed1.Count();
Med2num = listMed2.Count();
Med3num = listMed3.Count();
Med4num = listMed4.Count();
Med5num = listMed5.Count();
SetText(Med1num, Med2num, Med3num, Med4num, Med5num);
}
}
像这样:
/// <summary>The group</summary>
enum eGroup : byte
{
A, B, C, D, E
};
static IEnumerable<eGroup> allGroups()
{
return Enum.GetValues( typeof( eGroup ) ).Cast<eGroup>();
}
/// <summary>Classify tag to the group, returns null if failed.</summary>
static eGroup? classify( Tag tag )
{
string str = tag.Epc.ToString().ToUpper();
foreach( eGroup e in allGroups() )
if( str.Contains( e.ToString ) )
return e;
return null;
}
/// <summary>Add tag to list unless it's already there.</summary>
static void addToList( List<Tag> list, Tag t )
{
int ind = list.IndexOf( t );
if( ind < 0 )
list.Add( t ); // Not on the list
else if( list[ ind ].LastSeenTime.Utc < t.LastSeenTime.Utc )
list[ ind ] = t; // Only replace if newer then the existing one
}
/// <summary>The collection to hold all that groups.</summary>
readonly Dictionary<eGroup, List<Tag>> med = allGroups().ToDictionary( e => e, e => new List<Tag>() );
/// <summary>True if that tag is too old.</summary>
static bool isTooOld( Tag t )
{
ImpinjTimestamp ts = t.LastSeenTime;
DateTime utc = new DateTime( 1970, 1, 1, 0, 0, 0, DateTimeKind.Utc ).AddTicks( (long)ts.Utc * 10L );
return ( DateTime.UtcNow - utc ).TotalMilliseconds > 500;
}
void OnTagsReported( ImpinjReader sender, TagReport report )
{
// Classify and add to the correct group
foreach( Tag tag in report )
{
eGroup? group = classify( tag );
if( !group.HasValue ) continue;
addToList( med[ group.Value ], tag );
}
// Remove too old tags
foreach( var list in med.Values )
list.RemoveAll( isTooOld );
// Show counts
int[] c = allGroups().Select( e => med[ e ].Count ).ToArray();
SetText( c[ 0 ], c[ 1 ], c[ 2 ], c[ 3 ], c[ 4 ] );
}
在我看来,这就是您可能需要的全部内容:
void OnTagsReported(ImpinjReader sender, TagReport report)
{
tags.RemoveAll(tag => report.Select(r => r.Epc).Contains(tag.Epc));
tags.AddRange(report);
tags.RemoveAll(tag =>
{
Impinj.OctaneSdk.ImpinjTimestamp second = tag.LastSeenTime;
string milisecondsUTC = second.ToString();
long lastseen = Convert.ToInt64(milisecondsUTC);
TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
long secondsSinceEpoch = (long)t.TotalMilliseconds;
return secondsSinceEpoch - lastseen > 5000;
});
var counts =
new[] { "A", "B", "C", "D", "E", }
.Select(c =>
tags
.Where(tag => tag.Epc.ToString().IndexOf(c) != -1)
.Count())
.ToArray();
SetText(counts[0], counts[1], counts[2], counts[3], counts[4]);
}
counts
定义可能是唯一令人悲伤的事情,但如果这种基本的方法无法为您提供所需的结果,我可以让它发挥作用。
确保代码顶部有 using System.Linq;
。
这是我为测试目的创建的对象模型。它允许 OP 的代码和我的代码编译。
public void SetText(params int[] xs) { }
public class Impinj
{
public class OctaneSdk
{
public class TagData { }
public class ImpinjTimestamp { }
}
}
public class ImpinjReader { }
public class TagReport : List<Tag> { }
public class Tag
{
public ushort AntennaPortNumber;
public Impinj.OctaneSdk.TagData Epc;
public Impinj.OctaneSdk.ImpinjTimestamp LastSeenTime;
}
如果你想防止重复,你应该考虑使用 Sets。根据您的需要,TreeSet 可用于排序数据,在这种情况下,您必须确保 Tag 实现 IComparable。否则 HashSet 应该很合适。
如果您想继续使用列表,您 必须 覆盖 Tag 上的 Equals 方法。根据您的代码,我们看不到 Tag 的结构,但是您使用了 List.Contains 方法。您应该实施 Equals 而忽略 LastTimeSeen。
您也不应该以这种方式使用 IndexOf,因为它有点模糊代码,您应该能够将其替换为 String.Contains。按照 Enigmativity 的建议使用 Linq 也可以大大清理您的代码。
如果您无权访问该库的源代码,您应该在检查相等性的选择集合上创建一个辅助方法或扩展方法。
所以我有几个标签类型的列表。标签有几个属性:.Epc、.AntennaPortNumber 和 .LastTimeSeen。我想从主列表中取出所有标签,并将它们分类为 5 个较小的列表,但每个 .Epc 只保留一份副本,并且它必须是最新的 .LastTimeSeen。我什至不确定从哪里开始。我在想我一定需要对嵌套几次的 .GroupBy 做些什么?现在代码分为两个主要部分:我将新标签添加到它们所属的列表中,以及我删除一个 500 毫秒内未出现的标签。我试图用 .Contains 防止将重复的标签添加到 5 个子列表中,但是因为它们具有不同的 LastTimeSeen 属性,所以没有达到预期的效果。
感谢任何人可能提供的任何指导!
List<Tag> tags = new List<Tag>();
List<Tag> listMed1 = new List<Tag>();
List<Tag> listMed2 = new List<Tag>();
List<Tag> listMed3 = new List<Tag>();
List<Tag> listMed4 = new List<Tag>();
List<Tag> listMed5 = new List<Tag>();
void OnTagsReported(ImpinjReader sender, TagReport report)
{
// This event handler is called asynchronously
// when tag reports are available.
// Loop through each tag in the report
// and print the data.
//List<Tag> tags = new List<Tag>();
foreach (Tag tag in report)
{
ushort AntennaNum = tag.AntennaPortNumber;
Impinj.OctaneSdk.TagData first = tag.Epc;
string epcCheck = first.ToString().ToUpper();
Impinj.OctaneSdk.ImpinjTimestamp tim = tag.LastSeenTime;
if (epcCheck.IndexOf("A") != -1)
{
if (listMed1.Contains(tag) == false)
{
listMed1.Add(tag);
System. Diagnostics.Debug.WriteLine(epcCheck);
System.Diagnostics.Debug.WriteLine(tim);
}
}
else if (epcCheck.IndexOf("B") != -1)
{
if (listMed2.Contains(tag) == false)
{
listMed2.Add(tag);
}
}
else if (epcCheck.IndexOf("C") != -1)
{
if (listMed3.Contains(tag) == false)
{
listMed3.Add(tag);
}
}
else if (epcCheck.IndexOf("D") != -1)
{
if (listMed1.Contains(tag) == false)
{
listMed4.Add(tag);
}
}
else if (epcCheck.IndexOf("E") != -1)
{
if (listMed5.Contains(tag) == false)
{
listMed5.Add(tag);
}
}
int Med1num = listMed1.Count();
int Med2num = listMed2.Count();
int Med3num = listMed3.Count();
int Med4num = listMed4.Count();
int Med5num = listMed5.Count();
for (int loopr = 0; loopr < Med1num; loopr++)
{
Impinj.OctaneSdk.ImpinjTimestamp second = listMed1[loopr].LastSeenTime;
string milisecondsUTC = second.ToString();
long lastseen = Convert.ToInt64(milisecondsUTC);
TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
long secondsSinceEpoch = (long)t.TotalMilliseconds;
if (secondsSinceEpoch - lastseen > 500 )
{
listMed1.RemoveAt(loopr);
loopr = -1;
}
}
for (int loopr = 0; loopr < Med2num; loopr++)
{
Impinj.OctaneSdk.ImpinjTimestamp second = listMed2[loopr].LastSeenTime;
string milisecondsUTC = second.ToString();
long lastseen = Convert.ToInt64(milisecondsUTC);
TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
long secondsSinceEpoch = (long)t.TotalMilliseconds;
if (secondsSinceEpoch - lastseen > 500)
{
listMed2.RemoveAt(loopr);
loopr = -1;
}
}
for (int loopr = 0; loopr < Med3num; loopr++)
{
Impinj.OctaneSdk.ImpinjTimestamp second = listMed3[loopr].LastSeenTime;
string milisecondsUTC = second.ToString();
long lastseen = Convert.ToInt64(milisecondsUTC);
TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
long secondsSinceEpoch = (long)t.TotalMilliseconds;
if (secondsSinceEpoch - lastseen > 500)
{
listMed3.RemoveAt(loopr);
loopr = -1;
}
}
for (int loopr = 0; loopr < Med4num; loopr++)
{
Impinj.OctaneSdk.ImpinjTimestamp second = listMed4[loopr].LastSeenTime;
string milisecondsUTC = second.ToString();
long lastseen = Convert.ToInt64(milisecondsUTC);
TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
long secondsSinceEpoch = (long)t.TotalMilliseconds;
if (secondsSinceEpoch - lastseen > 500)
{
listMed4.RemoveAt(loopr);
loopr = -1;
}
}
for (int loopr = 0; loopr < Med5num; loopr++)
{
Impinj.OctaneSdk.ImpinjTimestamp second = listMed5[loopr].LastSeenTime;
string milisecondsUTC = second.ToString();
long lastseen = Convert.ToInt64(milisecondsUTC);
TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
long secondsSinceEpoch = (long)t.TotalMilliseconds;
if (secondsSinceEpoch - lastseen > 500)
{
listMed5.RemoveAt(loopr);
loopr = -1;
}
}
Med1num = listMed1.Count();
Med2num = listMed2.Count();
Med3num = listMed3.Count();
Med4num = listMed4.Count();
Med5num = listMed5.Count();
SetText(Med1num, Med2num, Med3num, Med4num, Med5num);
}
}
像这样:
/// <summary>The group</summary>
enum eGroup : byte
{
A, B, C, D, E
};
static IEnumerable<eGroup> allGroups()
{
return Enum.GetValues( typeof( eGroup ) ).Cast<eGroup>();
}
/// <summary>Classify tag to the group, returns null if failed.</summary>
static eGroup? classify( Tag tag )
{
string str = tag.Epc.ToString().ToUpper();
foreach( eGroup e in allGroups() )
if( str.Contains( e.ToString ) )
return e;
return null;
}
/// <summary>Add tag to list unless it's already there.</summary>
static void addToList( List<Tag> list, Tag t )
{
int ind = list.IndexOf( t );
if( ind < 0 )
list.Add( t ); // Not on the list
else if( list[ ind ].LastSeenTime.Utc < t.LastSeenTime.Utc )
list[ ind ] = t; // Only replace if newer then the existing one
}
/// <summary>The collection to hold all that groups.</summary>
readonly Dictionary<eGroup, List<Tag>> med = allGroups().ToDictionary( e => e, e => new List<Tag>() );
/// <summary>True if that tag is too old.</summary>
static bool isTooOld( Tag t )
{
ImpinjTimestamp ts = t.LastSeenTime;
DateTime utc = new DateTime( 1970, 1, 1, 0, 0, 0, DateTimeKind.Utc ).AddTicks( (long)ts.Utc * 10L );
return ( DateTime.UtcNow - utc ).TotalMilliseconds > 500;
}
void OnTagsReported( ImpinjReader sender, TagReport report )
{
// Classify and add to the correct group
foreach( Tag tag in report )
{
eGroup? group = classify( tag );
if( !group.HasValue ) continue;
addToList( med[ group.Value ], tag );
}
// Remove too old tags
foreach( var list in med.Values )
list.RemoveAll( isTooOld );
// Show counts
int[] c = allGroups().Select( e => med[ e ].Count ).ToArray();
SetText( c[ 0 ], c[ 1 ], c[ 2 ], c[ 3 ], c[ 4 ] );
}
在我看来,这就是您可能需要的全部内容:
void OnTagsReported(ImpinjReader sender, TagReport report)
{
tags.RemoveAll(tag => report.Select(r => r.Epc).Contains(tag.Epc));
tags.AddRange(report);
tags.RemoveAll(tag =>
{
Impinj.OctaneSdk.ImpinjTimestamp second = tag.LastSeenTime;
string milisecondsUTC = second.ToString();
long lastseen = Convert.ToInt64(milisecondsUTC);
TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
long secondsSinceEpoch = (long)t.TotalMilliseconds;
return secondsSinceEpoch - lastseen > 5000;
});
var counts =
new[] { "A", "B", "C", "D", "E", }
.Select(c =>
tags
.Where(tag => tag.Epc.ToString().IndexOf(c) != -1)
.Count())
.ToArray();
SetText(counts[0], counts[1], counts[2], counts[3], counts[4]);
}
counts
定义可能是唯一令人悲伤的事情,但如果这种基本的方法无法为您提供所需的结果,我可以让它发挥作用。
确保代码顶部有 using System.Linq;
。
这是我为测试目的创建的对象模型。它允许 OP 的代码和我的代码编译。
public void SetText(params int[] xs) { }
public class Impinj
{
public class OctaneSdk
{
public class TagData { }
public class ImpinjTimestamp { }
}
}
public class ImpinjReader { }
public class TagReport : List<Tag> { }
public class Tag
{
public ushort AntennaPortNumber;
public Impinj.OctaneSdk.TagData Epc;
public Impinj.OctaneSdk.ImpinjTimestamp LastSeenTime;
}
如果你想防止重复,你应该考虑使用 Sets。根据您的需要,TreeSet 可用于排序数据,在这种情况下,您必须确保 Tag 实现 IComparable。否则 HashSet 应该很合适。
如果您想继续使用列表,您 必须 覆盖 Tag 上的 Equals 方法。根据您的代码,我们看不到 Tag 的结构,但是您使用了 List.Contains 方法。您应该实施 Equals 而忽略 LastTimeSeen。
您也不应该以这种方式使用 IndexOf,因为它有点模糊代码,您应该能够将其替换为 String.Contains。按照 Enigmativity 的建议使用 Linq 也可以大大清理您的代码。
如果您无权访问该库的源代码,您应该在检查相等性的选择集合上创建一个辅助方法或扩展方法。