C# C非邪恶快速数组查找?

C# C非邪恶快速数组查找?,c#,arrays,performance,dictionary,C#,Arrays,Performance,Dictionary,我希望有大量类实例返回相同的相似数据字段,如本示例实现中所示: foreach (SomeClass sc in SomeClasses) { System.Console.WriteLine(sc.GetData("1st field")); System.Console.WriteLine(sc.GetData("Another field")); System.Console.WriteLine(sc.GetData("and another")); } // -

我希望有大量类实例返回相同的相似数据字段,如本示例实现中所示:

foreach (SomeClass sc in SomeClasses)
{
    System.Console.WriteLine(sc.GetData("1st field"));
    System.Console.WriteLine(sc.GetData("Another field"));
    System.Console.WriteLine(sc.GetData("and another"));
}

// ---- inside SomeClass:

Dictionary<string, string> myData;

public string GetData(string field)
{
    return myData[field];
}
现在,字段查找是有效的,但在这些数组中,它感觉不太对劲。这是一个非常糟糕的时刻,而且处理字段_键整数既繁琐又容易出错

我不知道我是否在追求性能幽灵,只是我想找到一个既高效又干净的设计


建议?

你为什么不查字典呢?字典的一个非常有效的实现是对数组中的哈希进行索引查找。因此,底层实现可以归结为第二个示例中的代码。这将使它成为O1


使用字典你为什么不查字典呢?字典的一个非常有效的实现是对数组中的哈希进行索引查找。因此,底层实现可以归结为第二个示例中的代码。这将使它成为O1


使用字典

如果实例具有相同的字段,为什么不使用属性呢

foreach (SomeClass sc in SomeClasses)
{
    System.Console.WriteLine(sc.FirstField);
    System.Console.WriteLine(sc.AnotherField);
    System.Console.WriteLine(sc.AndAnother);
}

如果实例具有相同的字段,为什么不使用属性呢

foreach (SomeClass sc in SomeClasses)
{
    System.Console.WriteLine(sc.FirstField);
    System.Console.WriteLine(sc.AnotherField);
    System.Console.WriteLine(sc.AndAnother);
}

首先,如果您不确定这实际上是一个性能问题,那么是的,您正在追踪性能重影,并且您当前的实现很好

但是,如果您在分析过程中发现确实需要加快这段代码的速度,那么您的代码看起来很好。“数组是邪恶的”通常只在公共接口中适用,使用它们来实现也没关系


不过,我想对您的代码做一点修改:创建一个包含字段的枚举,并使用它而不是int。它同样快速,可读性也更高。如果在编译时字段未知,则可以使用int。如果您在编译时确实知道一些字段,那么可以对它们使用静态属性。

首先,如果您不确定这实际上是一个性能问题,那么是的,您正在跟踪性能重影,并且您当前的实现是好的

但是,如果您在分析过程中发现确实需要加快这段代码的速度,那么您的代码看起来很好。“数组是邪恶的”通常只在公共接口中适用,使用它们来实现也没关系


不过,我想对您的代码做一点修改:创建一个包含字段的枚举,并使用它而不是int。它同样快速,可读性也更高。如果在编译时字段未知,则可以使用int。如果您在编译时确实知道一些字段,那么可以对它们使用静态属性。

因为这些字段在编译时是未知的,而是动态的和用户可配置的,所以我将稍微修改您的示例程序以使用属性数组。然后我会提倡一种类似于您的方法,但在这里使用您自己的自定义类,称为MyProperty而不是string。性能至少和字符串方法一样好,也许比字符串方法好一点,但好处是它给了您更多的灵活性:如果您最终出于性能原因决定需要使用数组或列表方法,您可以轻松地将数组索引嵌入MyProperty类。您必须更改GetData的实现,但不能更改调用代码

public static void Test1() {
  SomeClass[] SomeClasses; //created somehow

  //in real life, this would be determined dynamically
  var properties=new[] {SomeClass.FirstField, SomeClass.AnotherField, SomeClass.AndAnother};

  foreach(var sc in SomeClasses) {
    foreach(var property in properties) {
      Console.WriteLine(sc.GetData(property));
    }
  }
}

public class SomeClass {
  public static readonly MyProperty FirstField=new MyProperty();
  public static readonly MyProperty AnotherField=new MyProperty();
  public static readonly MyProperty AndAnother=new MyProperty();

  private readonly Dictionary<MyProperty, string> myData=new Dictionary<MyProperty, string>();

  public string GetData(MyProperty property) {
    return myData[property];
  }
}

//default implementation of Equals and GetHashCode are fine here
public class MyProperty {}
然而,由于您的目标应用程序实际上是收集一组动态的和用户可配置的属性获取程序,所以您可能真的想创建一些函数?下面这样的代码将非常快,并且它仍然具有您想要的功能,即它允许您创建一个动态的、用户可配置的属性获取程序列表

public static void Test2() {
  SomeClass[] SomeClasses; //created somehow

  //in real life, this would be determined dynamically
  var getters=new[] {SomeClass.FirstField, SomeClass.AnotherField, SomeClass.AndAnother};
  foreach(var sc in SomeClasses) {
    foreach(var getter in getters) {
      System.Console.WriteLine(getter(sc));
    }
  }
}

public class SomeClass {
  public static readonly Func<SomeClass, string> FirstField=sc => sc.field0;
  public static readonly Func<SomeClass, string> AnotherField=sc => sc.field1;
  public static readonly Func<SomeClass, string> AndAnother=sc => sc.field2;

  private string field0;
  private string field1;
  private string field2;
}

因为这些字段在编译时是未知的,而是动态的和用户可配置的,所以我将稍微修改您的示例程序以使用属性数组。然后我会提倡一种类似于您的方法,但在这里使用您自己的自定义类,称为MyProperty而不是string。性能至少和字符串方法一样好,也许比字符串方法好一点,但好处是它给了您更多的灵活性:如果您最终出于性能原因决定需要使用数组或列表方法,您可以轻松地将数组索引嵌入MyProperty类。您必须更改GetData的实现,但不能更改调用代码

public static void Test1() {
  SomeClass[] SomeClasses; //created somehow

  //in real life, this would be determined dynamically
  var properties=new[] {SomeClass.FirstField, SomeClass.AnotherField, SomeClass.AndAnother};

  foreach(var sc in SomeClasses) {
    foreach(var property in properties) {
      Console.WriteLine(sc.GetData(property));
    }
  }
}

public class SomeClass {
  public static readonly MyProperty FirstField=new MyProperty();
  public static readonly MyProperty AnotherField=new MyProperty();
  public static readonly MyProperty AndAnother=new MyProperty();

  private readonly Dictionary<MyProperty, string> myData=new Dictionary<MyProperty, string>();

  public string GetData(MyProperty property) {
    return myData[property];
  }
}

//default implementation of Equals and GetHashCode are fine here
public class MyProperty {}
然而,由于您的目标应用程序实际上是收集一组动态的和用户可配置的属性获取程序,所以您可能真的想创建一些函数?下面这样的代码将非常快,并且它仍然具有您想要的功能,即它允许您创建一个动态的、用户可配置的属性获取程序列表

public static void Test2() {
  SomeClass[] SomeClasses; //created somehow

  //in real life, this would be determined dynamically
  var getters=new[] {SomeClass.FirstField, SomeClass.AnotherField, SomeClass.AndAnother};
  foreach(var sc in SomeClasses) {
    foreach(var getter in getters) {
      System.Console.WriteLine(getter(sc));
    }
  }
}

public class SomeClass {
  public static readonly Func<SomeClass, string> FirstField=sc => sc.field0;
  public static readonly Func<SomeClass, string> AnotherField=sc => sc.field1;
  public static readonly Func<SomeClass, string> AndAnother=sc => sc.field2;

  private string field0;
  private string field1;
  private string field2;
}

这些字段在编译时未知。它们是动态的,用户可配置的。这些字段在编译时是未知的。它们是动态的,用户可以配置。是的,我可以让字典查找整数键。我想这是一个解决方案。问题:字段也由类表示。这是个好主意吗

有可能让字典查找这个类的对象吗?@Larsp问题就在这里。经验法则是永远不要预先优化。通过分析器运行代码,甚至还有一些免费的分析器。在分析应用程序之前,您一直在追踪重影。字典的效率非常高。@Andrew,但是计算哈希值取决于字符串的大小,所以它不是O1。@Andrew,这正是使用Big-O计算复杂性的工作原理。如果计算所需的时间取决于某个潜在的无界值,则不能说某个值是O1。可以缓存哈希,但是string.GetHashCode不是这样实现的。是的,我可以让字典查找整数键。我想这是一个解决方案。问题:字段也由类表示。让字典查找这个类的对象是一个好主意/可能吗?@Larsp问题就在这里。经验法则是永远不要预先优化。通过分析器运行代码,甚至还有一些免费的分析器。在分析应用程序之前,您一直在追踪重影。字典的效率非常高。@Andrew,但是计算哈希值取决于字符串的大小,所以它不是O1。@Andrew,这正是使用Big-O计算复杂性的工作原理。如果计算所需的时间取决于某个潜在的无界值,则不能说某个值是O1。可以缓存哈希,但string.GetHashCode不是这样实现的。事实上,我确实为非动态字段创建了枚举,但编译器要求我在查找数组之前将枚举成员强制转换为int,这让我很恼火:@Larsp:Yep,这很恼人。您可以使用一组公共常量创建一个静态类,但是编译器不会检查冲突。这个问题没有完美的答案。我想代码生成器可以从一个简单的标识符列表中创建int类型的常量,但这会使构建过程更加复杂带有公共常量的静态类是一个合理的选择,感谢提示。实际上,我为非动态字段创建了枚举,编译器要求我在查找数组之前将枚举成员强制转换为int,这让我很恼火:@Larsp:Yep,这太恼人了。您可以使用一组公共常量创建一个静态类,但是编译器不会检查冲突。这个问题没有完美的答案。我想代码生成器可以从一个简单的标识符列表中创建int类型的常量,但这会使构建过程更加复杂带有公共常量的静态类是一个合理的选择,谢谢提示。谢谢回复和代码示例。我确实有一个表示字段/属性的类,我想知道是否可以使用该类的实例进行字典查找而不会遇到麻烦。我没有想到func解决方案,非常有启发性,谢谢!对我来说,学习C语言比解决实际问题更重要。谢谢你的回复和代码示例。我确实有一个表示字段/属性的类,我想知道是否可以使用该类的实例进行字典查找而不会遇到麻烦。我没有想到func解决方案,非常有启发性,谢谢!对我来说,学习C语言比解决实际问题更重要。