Как преобразовать многомерный массив в словарь?
У меня есть массив размером 3 на 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!!!
Как я могу настроить это правильно?
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]});
Многомерные массивы - это непрерывный блок памяти, поэтому вам приходится обращаться с ними как с одним массивом. Попробуй это:
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]: Смотрите здесь документацию по анонимным типам.
Это самый простой подход, который я могу придумать:
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());
Это дает мне:
Вам просто нужно 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());
Я думаю, что ваш подход был правильным, мое единственное сомнение в том, что ваш массив статичен или нет?
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]}));
Примечание: я не смог выполнить и проверить код! Сожалею.
Я сделал с помощью 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));
}