【问题标题】:C# Dynamic Dictionary - Selecting Random Value from Dynamic ObjectC# 动态字典 - 从动态对象中选择随机值
【发布时间】:2020-02-04 16:10:25
【问题描述】:

我一直在探索动态字典作为将多个字符串与单个“ID”字符串相关联的潜在解决方案。我需要做的是将一系列 4 个字母的文本字符串分配给一个也是 4 个字母的文本字符串的键(每个字符串都是唯一的,范围为 AAAA-ZZZZ)。

键是 4 个字母的文本字符串,例如:“AAAA”、“AAGB”等。 每个键可以包含多个 4 字母的文本字符串:“ACFE”、“AAFE”等。

目标是选择一个键,然后随机选择其中一个动态值。我目前的测试设置如下:

// Dynamic objects
dynamic d1 = new System.Dynamic.ExpandoObject();  
dynamic d2 = new System.Dynamic.ExpandoObject();
dynamic d3 = new System.Dynamic.ExpandoObject();

var dict = new Dictionary<string, dynamic>();

// Assign dynamic objects to the Dictionary Key
dict["AAAA"] = d1;
dict["AAGB"] = d2;
dict["ABDA"] = d3;

// Populate the dynamic object with the value(s)
dict["AAAA"].FooBar = new { i1 = "ACFE", i2 = "AAFE", i3 = "CAED", i4 = "HSGB" };
dict["AAGB"].FooBar = new { i1 = "ZZZZ", i2 = "XXXX", i3 = "CAED", i4 = "HSGB" };
dict["ABDA"].FooBar = new { i1 = "YYYY", i2 = "WWWW", i3 = "CAED", i4 = "HSGB" };

string newName = dict["ABDA"].FooBar.i1;
return newName;

这会拉出正确的字符串。但是有没有办法设置它,这样我就可以随机提取其中一个值,而不必明确指定我要追求的值?或者我应该完全改变方法(我已经使用锯齿状数组做了类似的事情,并将使用它作为后备但对这个动态字典作为可能的替代方案感到好奇)。

【问题讨论】:

标签: c# dictionary random dynamic collections


【解决方案1】:

在您的情况下,假设您已经知道键和值的类型,您可能应该使用 Dictionary with expandable collection 作为值。合适的类型是

Dictionary<string, List<string>>

因此,您不会因使用动态运行时而产生过多开销,并且您可以像从任何集合中一样随机地从 List 推送和检索值。

【讨论】:

  • 这似乎是个好方法;我将改用 List.
【解决方案2】:

如果你想要一个不可变的集合(在集合创建后你不会添加到集合中),那么使用查找。如果您需要能够添加/删除条目,请使用字典。我已经包含了一个使用 IGrouping 的示例,但它对于查找来说是最慢的,因为您需要遍历直到找到密钥,但是如果您需要迭代所有密钥,就像您想为每个提取随机字符串一样,它非常有效键。

下面是一个使用 Lookup 的例子:

var values = new[] {
    new KeyValuePair<string,string> ("AAAA","ACFE"),
    new KeyValuePair<string,string> ("AAAA","AAFE"),
    new KeyValuePair<string,string> ("AAAA","CAED"),
    new KeyValuePair<string,string> ("AAAA","HSGB"),

    new KeyValuePair<string,string> ("AAGB","ZZZZ"),
    new KeyValuePair<string,string> ("AAGB","XXXX"),
    new KeyValuePair<string,string> ("AAGB","CAED"),
    new KeyValuePair<string,string> ("AAGB","HSGB"),

    new KeyValuePair<string,string> ("ABDA","YYYY"),
    new KeyValuePair<string,string> ("ABDA","WWWW"),
    new KeyValuePair<string,string> ("ABDA","CAED"),
    new KeyValuePair<string,string> ("ABDA","HSGB"),
};
// Convert array to a Lookup
var lookup=values.ToLookup(k=>k.Key, v=>v.Value);

// Retrieve random string from entry "AAAA"
var entry = lookup["AAAA"];
var rand = new Random();
var max = entry.Count();
var ans = entry.Skip(rand.Next(max)).First();

这是一个使用Dictionary&lt;string,List&lt;string&gt;&gt;的例子:

var values = new[] {
    new KeyValuePair<string,string> ("AAAA","ACFE"),
    new KeyValuePair<string,string> ("AAAA","AAFE"),
    new KeyValuePair<string,string> ("AAAA","CAED"),
    new KeyValuePair<string,string> ("AAAA","HSGB"),

    new KeyValuePair<string,string> ("AAGB","ZZZZ"),
    new KeyValuePair<string,string> ("AAGB","XXXX"),
    new KeyValuePair<string,string> ("AAGB","CAED"),
    new KeyValuePair<string,string> ("AAGB","HSGB"),

    new KeyValuePair<string,string> ("ABDA","YYYY"),
    new KeyValuePair<string,string> ("ABDA","WWWW"),
    new KeyValuePair<string,string> ("ABDA","CAED"),
    new KeyValuePair<string,string> ("ABDA","HSGB"),
};
//Convert array to Dictionary<string,List<String>>
var dict = values.GroupBy(k=>k.Key)
  .ToDictionary(k=>k.Key,v=>v.Select(kvp=>kvp.Value).ToList());

// Retrieve random string from entry "AAAA"
var entry = lookup["AAAA"];
var rand = new Random();
var max = entry.Count();
var ans = entry.Skip(rand.Next(max)).First();

这是一个使用 IGrouping 的示例:

var values = new[] {
    new KeyValuePair<string,string> ("AAAA","ACFE"),
    new KeyValuePair<string,string> ("AAAA","AAFE"),
    new KeyValuePair<string,string> ("AAAA","CAED"),
    new KeyValuePair<string,string> ("AAAA","HSGB"),

    new KeyValuePair<string,string> ("AAGB","ZZZZ"),
    new KeyValuePair<string,string> ("AAGB","XXXX"),
    new KeyValuePair<string,string> ("AAGB","CAED"),
    new KeyValuePair<string,string> ("AAGB","HSGB"),

    new KeyValuePair<string,string> ("ABDA","YYYY"),
    new KeyValuePair<string,string> ("ABDA","WWWW"),
    new KeyValuePair<string,string> ("ABDA","CAED"),
    new KeyValuePair<string,string> ("ABDA","HSGB"),
};
//Convert array to IGrouping<string,string>
var group = values.GroupBy(k=>k.Key);

// Retrieve random string from entry "AAAA"
var entry = group.First(k=>k.Key == "AAAA");
var rand = new Random();
var max = entry.Count();
var ans = entry.Skip(rand.Next(max)).First().Value;

【讨论】:

    【解决方案3】:

    您应该完全改变您的方法。 dynamic 适用于您对正在处理的对象的 shape 有所了解的情况(例如,它具有 FooBari1 属性),但您不知道知道在编译时它将是什么type(可能来自无类型语言,如 JavaScript 或 Python)。

    如果您的用例不符合这些标准,我会说您最好将字典用于您不知道(在编译时)您想要哪一部分数据的任何事情(例如提取值随机输出),并为在编译时应该知道的形状使用强类类型和接口。

    【讨论】:

      【解决方案4】:

      使用 Base26 创建数字

          class Program
          {
              static void Main(string[] args)
              {
                  Base26 base26 = new Base26();
                  for(int i = 0; i < base26.MAX_NUM; i++) 
                  {
                      Console.WriteLine(base26.ToString());
                  }
                  Console.ReadLine();
              }
          }
          public class Base26
          {
              public int MAX_NUM = (int)Math.Pow(26, 4);
              int current = 0;
      
              public override string ToString()
              {
                  byte[] base26 = new byte[4];
                  base26[3] = (byte)(current % 26);
                  base26[2] = (byte)((current / 26) % 26);
                  base26[1] = (byte)((current / (26 * 26)) % 26);
                  base26[0] = (byte)((current / (26 * 26 * 26)) % 26);
                  current++;
                  if (current == MAX_NUM) current = 0;
      
                  return string.Join("", base26.Select(x => (char)(((byte)'A') + x)));
              } 
          }
      

      【讨论】:

      • 在这种情况下,一个 int 就足够了,因为 26^4 只有 456,976。
      猜你喜欢
      • 2016-04-14
      • 2012-10-04
      • 1970-01-01
      • 2014-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-19
      • 1970-01-01
      相关资源
      最近更新 更多