C# 优化双foreach循环

C# 优化双foreach循环,c#,dictionary,C#,Dictionary,我有一个双foreach循环,并希望通过使其成为一个而不是两个循环来加速它 其思想是从字典中提取一个元素,并将其与字典中的所有元素进行比较 foreach (KeyValuePair<Int64, string> kvp in originCounts) { foreach (KeyValuePair<Int64, string> testkvp in originCounts) { //Run Comparison on testkvp ad k

我有一个双foreach循环,并希望通过使其成为一个而不是两个循环来加速它

其思想是从字典中提取一个元素,并将其与字典中的所有元素进行比较

foreach (KeyValuePair<Int64, string> kvp in originCounts)
{
    foreach (KeyValuePair<Int64, string> testkvp in originCounts)
    {
    //Run Comparison on testkvp ad kvp
    }
}
foreach(原始计数中的KeyValuePair kvp)
{
foreach(原始计数中的KeyValuePair testkvp)
{
//在testkvp和kvp上运行比较
}
}

我想把它变成一个循环,有什么建议吗?

为什么要将词典条目与同一词典中的其他条目进行比较?你在检查重复的吗?如果是这样,您可以使用
originCounts.Distinct()


编辑:您需要为
Distinct
方法指定
IEqualityComparer
,否则它将只比较键(在
字典中总是不同的),而不是值。

您可以使用linq语法尝试此操作并比较性能

e、 g

foreach(原始计数中的键值对kvp1.SelectMany(kvp1=>originCounts.Select(testkvp=>kvp1),(kvp1,kvp=>kvp1)){
}

foreach(KeyValuePair kvp1 in从kvp1 in原始计数
从原始计数中的kvp中选择(testkvp=>kvp1)
选择kvp1){
}

您可以创建实现该接口的可比较字符串键值类

public class ComparableString : IComparable
{
    public Int64 Key { get; set; }

    public string Value { get; set; }

    public int CompareTo(object obj)
    {
        if (obj == null) return 1;

        string otherString = obj as ComparableString;

        if (otherString != null)
        {
            // PLACE YOUR COMPARE LOGIC HERE
            return this.Value.CompareTo(otherString.Value);
        }
        else
        {
            throw new ArgumentException("Object is not a Comparable String");
        }
    }
}
完成此操作后,您可以创建一个链表并运行.sort方法

var originCounts= new List<ComparableString>();
// Logic to fill your list
originCounts.Sort();
var originCounts=new List();
//填写清单的逻辑
originCounts.Sort();
.Sort方法的平均复杂度为O(n(logn)),最坏情况为O(n^2)。有关详细信息,请参阅


调用.Sort()方法后,您将知道,项目索引之前的任何值都小于或等于项目的值,而大于当前索引的任何索引都大于或等于项目的值。

也许我误解了这个问题,将其简化了,但是,如果您只是试图在字符串中查找重复的值,则可以使用字典的Values属性,并对其执行Distinct操作

以词典为例:

    Dictionary<Int64, string> originalCounts = new Dictionary<Int64, string>();
    for (Int64 i = 0; i < 10; i++)
    {
        originalCounts.Add(i, i.ToString());
    }
    originalCounts[5] = originalCounts[3];

    foreach (var kvp in originalCounts)
    {
        Console.WriteLine("{0}  {1}", kvp.Key, kvp.Value);
    }

    Console.WriteLine();

    foreach (var value in originalCounts.Values.Distinct())
    {
        Console.WriteLine("{0}", value);
    }
Dictionary originalCounts=new Dictionary();
对于(Int64 i=0;i<10;i++)
{
添加(i,i.ToString());
}
原始账户[5]=原始账户[3];
foreach(原始账户中的var kvp)
{
WriteLine(“{0}{1}”,kvp.Key,kvp.Value);
}
Console.WriteLine();
foreach(originalCounts.Values.Distinct()中的var值)
{
WriteLine(“{0}”,值);
}
您可以使用检查所有元素是否相同:

var firstID = originCounts.First().Value.UserID;
bool allEquals = originCounts.Skip(1).All(o => o.Value.UserID == firstID);
看来这才是你真正想要的

我刚刚在中选择了一个类字段,听起来是一个合理的标识符

public class MyObject 
{
    public string FirstName{ get; set; }
    public string LastName{ get; set; }
    public int UserID { get; set; }
    public string Address { get; set; }
}
编辑:根据您的评论,您希望确定是否有任何对象的字段与另一个对象的相同字段不同

var first = originCounts.First().Value;
bool allEquals = originCounts.Skip(1).All(o =>
                o.Value.FirstName == first.FirstName
             && o.Value.LastName  == first.LastName
             && o.Value.UserID    == first.UserID
             && o.Value.Address   == first.Address);

如果我理解正确,要获取不同的对象(不实现IComparable或重写Equals和GetHashcode):


你想用什么方式来比较呢?如果它不是“按键”,那么除了O(N^2)之外,你就不能真正做到这一点——或者,如果你想变得优雅,可能只有一半(但O(N^2)的一半仍然是O(N^2))。基本上,我们需要看看你在评论什么。你的目的是什么?你想做什么?也许你可以玩一下
.Distinct
扩展方法,让框架完成工作?量子计算到LINQ??你想要什么还不清楚。也许您可以填写
//运行比较…
部分。如果KeyValuePairs来自字典,则键(至少)都是不同的,因此
不同的
不会过滤掉任何内容。您是对的,必须指定一个比较器来比较
字段。所做的只是使用不同的语法;这并不会减少它的工作量,而且很容易使它的性能变差。坦率地说,嵌套的--
foreach
也更容易阅读和理解。我想不出有什么好的理由这么做……我同意你的观点,马克,可读性非常重要。嵌套的foreach更容易阅读和理解。这不只是检查第一个元素吗?@Badmiral:是的,但是如果不是所有元素都相同,与不同的元素相比,它在第一个元素上也会返回
false
。因此,您不需要将“全部”与“全部”进行比较,而只需将“第一个”与“全部”进行比较。是的,我希望实现它,这样,对于每一个,我就知道哪些是重复的(因为这些对于我的目的很重要)。是否有实现此功能的方法来与所有值进行比较?(我还想知道它是否等于MyObject的任何元素。谢谢!@Badmiral:那么如果任何对象的字段与另一个对象的字段不同,你想返回false吗?编辑我的答案以将其考虑在内。
public class MyObject 
{
    public string FirstName{ get; set; }
    public string LastName{ get; set; }
    public int UserID { get; set; }
    public string Address { get; set; }
}
var first = originCounts.First().Value;
bool allEquals = originCounts.Skip(1).All(o =>
                o.Value.FirstName == first.FirstName
             && o.Value.LastName  == first.LastName
             && o.Value.UserID    == first.UserID
             && o.Value.Address   == first.Address);
var noDups = originCounts
                                 //Any Prop. you want to compare
              .GroupBy(o => new { o.FirstName, o.LastName, o.UserID, o.Address })
              .Select(g => g.First())
              .ToList();