如何将多维数组转换为字典?

7

我有一个 n 行 3 列的数组,希望将其转换为 Dictionary<string,string[]>,其中第一列作为键,剩下的列作为值的数组。

例如:

Key = arr[0,0], Value = new string[2] {arr[0,1], arr[0,2]}.

我知道ToDictionary,但我不知道如何设置值部分。

arr.ToDictionary(x=>arr[x,0],x=>new string[2]{arr[x,1],arr[x,2]});
//This doesn't work!!!

如何正确设置它?

1
这是一个多维数组还是交错数组?你的例子暗示了它是交错数组。 - MineR
它是多维的。 - Pikachu620
1
@Pikachu620 - 如果它是多维的,那么键不能是 arr[0][0] - 它必须是 arr[0, 0]。那是哪一个? - Enigmativity
我的错!我会去编辑它的!!! - Pikachu620
5个回答

7
多维数组是内存连续的一块,因此你需要像对待一个单一的数组一样处理它们。尝试以下代码:
var dict = arr.Cast<string>() 
  .Select((s, i) => new { s, i })
  .GroupBy(s => s.i / arr.GetLength(1))
  .ToDictionary(
    g => g.First().s,
    g => g.Skip(1).Select(i => i.s).ToArray()
  );

带有解释:

// First, cast it to an IEnumerable<string>
var dict = arr.Cast<string>() 

  // Use the Select overload that lets us get the index of the element,
  // And we capture the element's index (i), along with the element itself (s)
  // and put them together into an anonymous type [1]
  .Select((s, i) => new { s, i })

  // .GetLength(dimension) is a method on multidimensional arrays to 
  // get the length of a given dimension (pretty self-explanatory)
  // In this case, we want the second dimension, or how wide each 
  // row is: [x,y] <- we want y
  // Divide the element index (s.i) by that length to get the row index 
  // for that element
  .GroupBy(s => s.i / arr.GetLength(1))

  // Now we have an Grouping<int, IEnumerable<anonymous{string,int}>>
  .ToDictionary(

    // We don't care about the key, since it's the row index, what we want
    // is the string value (the `s` property) from first element in the row
    g => g.First().s,

    // For the value, we want to skip the first element, and extract
    // the string values (the `s` property), and then convert to an array
    g => g.Skip(1).Select(i => i.s).ToArray()
  );

[1]: 请参阅此处有关匿名类型的文档。


增加了一些解释,希望能让事情更清晰明了。 - rossipedia
嗯,可读性可能是主观的,但我完全同意性能方面的观点。当涉及到分配和性能时,LINQ通常可能非常糟糕。 - rossipedia
你的回答很好!但是太复杂了!我选择了比你的更简单的答案,希望你能理解! - Pikachu620
当然!重要的是你找到了一个适合自己的答案,帮助你完成工作 :) - rossipedia
var dict = arr.Cast<string>().Select((s, i) => new { s, i }).GroupBy(s => s.i / arr.GetLength(1)).ToDictionary(g => g.First().s,g => g.Skip(1).Select(i => i.s).ToArray());Enumerable.Range(0, arr.GetLength(0)).ToDictionary(i => arr[i, 0], i => new string[] {arr[i, 1], arr[i, 2]}); 相比,因为我永远记不住第一个,而第二个我可以! - Pikachu620
显示剩余4条评论

5
有时候不使用linq更易于阅读和更快:
 var dict = new Dictionary<string, string[]>();
 for (int i = 0; i < arr.GetLength(0); i++)
      dict[arr[i, 0]] = new string[] { arr[i, 1], arr[i, 2] };

但当你真的需要使用Linq时:

 Enumerable.Range(0, arr.GetLength(0))
     .ToDictionary(i => arr[i, 0], i => new string[] {arr[i, 1], arr[i, 2]});

Linq 部分和我的一样,但它不起作用!抱歉! - Pikachu620
@Pikachu620 不,它使用了一个 Enumerable.Range,这是你原来尝试中所缺少的,然后它就可以工作了。在这里可以看到一个工作示例:https://dotnetfiddle.net/Hig7rW - MineR
它起作用了!谢谢!我已经将被采纳的答案改成了你的! - Pikachu620

2
这是我能想到的最简单的方法:

var arr = new int[4, 3]
{
    { 1, 2, 3 },
    { 3, 5, 7 },
    { 5, 8, 11 },
    { 7, 11, 15 },
};

var dict = arr.Cast<int>().Buffer(3).ToDictionary(x => x[0], x => x.Skip(1).ToArray());

这给了我:

dict

您只需要使用NuGet获取“System.Interactive”即可获得Buffer运算符。
或者使用此实现:
public static IEnumerable<T[]> Buffer<T>(this IEnumerable<T> source, int count)
    =>
        source
            .Select((t, i) => new { t, i })
            .GroupBy(x => x.i / count)
            .Select(x => x.Select(y => y.t).ToArray());

1
我猜你的方法是正确的,我唯一的疑问是你的数组是静态的还是动态的?
arr.Select((value, index) => new { value, index }) .ToDictionary(x => x.index, x => new string[2]{x.value[x.index][1],x.value[x.index][2]}));

注意:我无法执行并检查代码!抱歉。

很抱歉,它不行! - Pikachu620

1

我曾经使用Integer完成了这个任务。请根据你的需求进行更改。

public static void Main()
{ 
    int row=0 , col=0;
    int[,] array = new int[,]
    {
     { 1, 2, 3 },
     { 4, 5, 6 }, 
     { 7, 8, 9 },
     { 10, 11, 12 } 
    };

    int flag=0;

    for (int i = 0; i < array.Rank; i++)
    {
                if(flag==0)
                {
        row= array.GetLength(i);
                    flag=1;
                }
                else
                {

         col= array.GetLength(i);       
                }

        }

    Dictionary<int,int[,]> dictionary = new Dictionary<int, int[,]>();

    for(int i=0;i<row;i++)
    {

        dictionary.Add(array[i,0],new int[, ]{{array[i,1]},{array[i,2]}});

    }

    Console.WriteLine(dictionary[4].GetValue(0,0));

}

谢谢你的回答。但我更喜欢Linq方法! - Pikachu620

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接