在KeyValuePair(C#)中找到最近的键

时间:2019-07-04 17:39:23

标签: c# linq dictionary keyvaluepair

我正在尝试查找与现有字典相比在顺序上符合条件的最接近的元素组。目标是采用包含特定顺序的字符串值的第一组元素。就我而言,我可能有一个更大的列表,看起来像这样:

{1, "ISO"}
{2, "AEA"}
...
{256, "OI"}
...
{302, "OI"}
{303, "N2"}
{304, "N2.5"}
...
{400, "N2"}

此操作的目的是查找包含特定顺序值的键值对,并从这些键值对中返回LOWEST键。为了使我感到半途而废,我提取了包含值“ OI”,“ N2”和“ N2.5”的线对的所有可能性。

假设我有一个字典,它像这样构建:

Dictionary map = new Dictionary<int,string>();

map.Add(new KeyValuePair<int, string>(256, "OI");
map.Add(new KeyValuePair<int, string>(302, "OI");
map.Add(new KeyValuePair<int, string>(303, "N2");
map.Add(new KeyValuePair<int, string>(304, "N2.5");
map.Add(new KeyValuePair<int, string>(400, "N2");

我想从此Dictionary中提取其键最接近的元素,以便以升序获得列表,例如包含302、303和304作为键的KeyValuePairs。最好的方法是什么?

2 个答案:

答案 0 :(得分:1)

然后我们去:

StatDensity2d$default_aes
#> Aesthetic mapping: 
#> * `colour` -> "#3366FF"
#> * `size`   -> 0.5
StatDensity2d$default_aes <- aes()

ggplot(df, aes(V1, V2)) +
  stat_density_2d(geom = "polygon") +
  geom_point(aes(colour = cut_number(V1, 5)))

输出:

    Dictionary<int, string> map = new Dictionary<int, string>();

    map.Add(256, "OI");
    map.Add(302, "OI");
    map.Add(303, "N2");
    map.Add(304, "N2.5");
    map.Add(400, "N2");
    var minDiffGroup = map.SelectMany(item1 =>
         map
         .Where(item2 => !object.Equals(item1, item2))
         .Select(item2 => new { Diff = Math.Abs(item1.Key - item2.Key), Item1 = item1, Item2 = item2 })
      )
      .GroupBy(item => item.Diff)
      .OrderBy(group => group.Key)
      .FirstOrDefault();

    Console.WriteLine("Diff: {0}", minDiffGroup.Key);
    foreach (var item in minDiffGroup)
        Console.WriteLine("Item 1: {0}\tItem 2:{1}", item.Item1, item.Item2);
    Console.ReadKey();

我会进一步帮助您,但是您的问题非常模糊。

修改

好的,在您添加了更多信息之后,我更改了lamda表达式:

Diff: 1
Item 1: [302, OI]       Item 2:[303, N2]
Item 1: [303, N2]       Item 2:[302, OI]
Item 1: [303, N2]       Item 2:[304, N2.5]
Item 1: [304, N2.5]     Item 2:[303, N2]

输出:

    Dictionary<int, string> map = new Dictionary<int, string>();

    map.Add(256, "OI");
    map.Add(302, "OI");
    map.Add(303, "N2");
    map.Add(304, "N2.5");
    map.Add(400, "N2");
    var orderedMap = map.OrderBy(item => item.Key); // Order the map
    var minDiffGroup = orderedMap.SelectMany(item1 =>
         orderedMap
         .SkipWhile(item2 => !object.Equals(item1, item2)) //skip all elements which were already merged
         .Skip(1) //skip item1 == item2
         .Select(item2 => new { Diff = Math.Abs(item1.Key - item2.Key), Item1 = item1, Item2 = item2 }) //create an unknown type with Key = diff and both items
      )
      .GroupBy(item => item.Diff) //group by Diff
      .OrderBy(group => group.Key) //order by Diff
      .FirstOrDefault(); //Take the smallest group

    if (minDiffGroup?.Count() > 0)
    {
        var lowestChain = minDiffGroup
             .OrderBy(item => item.Item1.Key) //order by the key of item1
             .TakeWhile(item => item.Item1.Key + minDiffGroup.Key == item.Item2.Key) //take all items as long as the next item has the difference of this group (otherwise there is a gap)
             .SelectMany(item => new List<KeyValuePair<int, string>>() { item.Item1, item.Item2 }) //select all collected KeyValuePairs
             .Distinct(); //take every once
        foreach (var item in lowestChain)
        {
            Console.WriteLine(item);
        }
    }

答案 1 :(得分:1)

如果您想同时从中学习,这里有一个基本的快速版本,带有详细说明。

总体逻辑是选择第一个项目,保持迭代直到不再是序列为止。然后检查是否至少迭代了2个连续数字(如果可以的话),请继续尝试下一个可用数字,直到所有数字都被迭代为止。

Dictionary<int, string> map = new Dictionary<int, string>();

map.Add(256, "OI");
map.Add(302, "OI");
map.Add(303, "N2");
map.Add(304, "N2.5");
map.Add(400, "N2");

// will contain the final results.
Dictionary<int, string> results = new Dictionary<int, string>();

// get map ordered
var mapList = map.OrderBy(o => o.Key).ToList();

// iterate until we have worked out each values
while (mapList.Any())
{
    // take first item
    var item = mapList[0];

    // kepp the index of found consecutive values                             
    var index = 0;

    // loop for each value
    for (int i = 1; i < mapList.Count; i++)
    {
        // if the value isn't 1 higher get out the loop
        if (mapList[i].Key != mapList[index].Key + 1)
        {
            break;
        }
        else
        {
            // value is more than 1 so keep going until we can't
            index++;
        }
    }

    // if we have found at least 2 consecutive numbers
    if (index > 0)
    {
        // add the first of the sequence
        results.Add(item.Key, item.Value);

        // add the rest of the sequence that was found
        for (int i = 0; i < index; i++)
        {
            results.Add(mapList[i + 1].Key, mapList[i + 1].Value);
        }

        // finally removed all items found plus the starting item (hence the + 1)
        mapList.RemoveRange(0, index + 1);
    }
    else
    {
        // no consecutive numbers found so just remove the item so we can loop and try the next one
        mapList.RemoveAt(0);
    }
}