Транспонировать коллекцию Custom с Linq - PullRequest
1 голос
/ 09 января 2020

У меня есть BindingList объектов, и у каждого объекта есть вложенный список элементов.

BindingList<QuoteboardRow> quoteboard = new BindingList<QuoteboardRow>();
quoteboard.Add(
    new QuoteboardRow()
    {
        Product= "Cement",
        Prices = new Dictionary<string, Price>() {
            { "SupplierA",
                new Price() { Low= 101, High= 102 }
            },
            { "SupplierB",
                new Price() { Low= 101, High= 102 }
            },
            { "SupplierC",
                new Price() { Low= 101, High= 102 }
            }
    }
);
dataGridView1.DataSource = quoteboard;

Если я просто привязываю коллекцию данных к представлению данных, это все, что я вижу:

enter image description here

Я хочу попробовать транспонировать коллекцию так, чтобы в ней был столбец для каждого из поставщиков и подколонка для цены Низкая и Высокая соответственно. В основном, как в кавычках с колонкой для каждого поставщика или если сетка данных по умолчанию поддерживает какую-то группировку: подколонки для низкой и высокой цены для каждого поставщика. Я вручную заполнил несколько ячеек таблицы данных, показывающих, чего я пытаюсь достичь:

enter image description here

Я пытался добиться прогресса с помощью кода, такого как этот фрагмент ниже, но безрезультатно.

var result = quoteboard
.SelectMany(x => x.Prices.Select((item, index) => new { Source = x.Product, item, index  }))
.GroupBy(i => i.index)
.Select(g => g.ToList())
.ToList();

Буду признателен за любую помощь в этом. В случае, если есть более удобный способ привязки данных к представлению и коллекции данных, это представление доступно только для чтения, и я буду обновлять коллекцию, чтобы отражать любые изменения в ценах.

Ответы [ 2 ]

1 голос
/ 09 января 2020

Я бы сделал это примерно так:

public class PriceWrap
{
    public string Product { get; set; }

    public string Supplier { get; set; }

    // you can also add all price fields here, if you only want one level
    public Price Price { get; set; }
}


var bl = new BindingList<PriceWrap>();

foreach (var quoteboard in quoteboards)
{
    foreach (var kv in quoteboard.Prices)
    {
        var supplier = kv.Key;
        var price = kv.Value;

        bl.Add(new PriceWrap() {
            Product = quoteboard.Product,
            Supplier = supplier,
            Price = price
        });
    }
}

dataGridView1.DataSource = bl;

Результат будет:

Product, SupplierA, LowA, HighA
Product, SupplierB, LowB, HighB
Product, SupplierC, LowC, HighC

1 голос
/ 09 января 2020

Вы можете попробовать использовать метод, который преобразует каждый элемент QuoteboardRow в новый тип, причем каждая цена указана как отдельный элемент.

Для каждого элемента, который должен быть напечатан «транспонированным» способом, вы должны взять объект и преобразовать его в тот же формат, что и у продукта / имени ... Dictionary<string, object>

Метод преобразования элемента в словарь

    public static Dictionary<string, object> ConvertItemToDictionary(QuoteboardRow x)
    {
        Dictionary<string, object> result = new Dictionary<string, object>();
        result.Add("Product", x.Product);
        foreach (var key in x.Prices.Keys)
        {
            x.Prices.TryGetValue(key, out Price price);
            result.Add($"{key}_L", price.Low);
            result.Add($"{key}_H", price.High);
        }
        return result;
    }

Используйте его в своем основном или другом процессе,

    BindingList<QuoteboardRow> quoteboard = new BindingList<QuoteboardRow>();
    quoteboard.Add(
        new QuoteboardRow()
        {
            Product = "Cement",
            Prices = new Dictionary<string, Price>() 
            {
                { "SupplierA",
                    new Price() { Low= 101, High= 102 }
                },
                { "SupplierB",
                    new Price() { Low= 101, High= 102 }
                },
                { "SupplierC",
                    new Price() { Low= 101, High= 102 }
                }
            }
        }
    );

    var result = quoteboard.Select(x => ConvertItemToDictionary(x)).ToList();


    Console.WriteLine(JsonConvert.SerializeObject(result, Formatting.Indented));
    dataGridView1.DataSource = result;

В консоли у меня было это в качестве вывода, что что бы правильно печатать транспонированным способом. (Я добавил столб в качестве второй записи для тестирования)

[
  {
    "Product": "Cement",
    "SupplierA_L": 101,
    "SupplierA_H": 102,
    "SupplierB_L": 101,
    "SupplierB_H": 102,
    "SupplierC_L": 101,
    "SupplierC_H": 102
  },
  {
    "Product": "pillar",
    "SupplierA_L": 101,
    "SupplierA_H": 104,
    "SupplierB_L": 101,
    "SupplierB_H": 101,
    "SupplierC_L": 101,
    "SupplierC_H": 105
  }
]
...