LINQ для замены нескольких столбцов на строки таблицы данных с помощью C # - PullRequest
0 голосов
/ 18 января 2012

У меня есть данные:

location    Quarter   ppl_required   ppl_available
BLR          Q1        70             35
BLR          Q2        50             45
BLR          Q3        25             28
BLR          Q4        60             58
CHN          Q1        77             92
CHN          Q2        42             66
CHN          Q3        29             20
CHN          Q4        22             24

Есть ли лучший способ получить приведенный ниже DataTable как вывод очень простым или коротким способом [ без циклов ] с использованием LINQ илис расширенными функциями LINQ с платформой .NET3.5 / 4.0 / 4.5.

Location  ppl_Required_Q1  ppl_Required_Q2  ppl_Required_Q3  ppl_Required_Q4  ppl_available_Q1  ppl_available_Q2  ppl_available_Q3  ppl_available_Q4
BLR       70               50               25               60               35                45                28                58
CHN       77               42               29               22               92                66                20                24

Ответы [ 2 ]

1 голос
/ 19 января 2012

Я создал структуру данных, аналогичную той, что вы описали в LINQPad. Это код, который у меня есть

void Main()
{
    List<Location> locations = new List<Location>
   {
      new Location { Key = "BLR", Quarter = "Q1", PeopleRequired = 70, PeopleAvailable = 35 },
      new Location { Key = "BLR", Quarter = "Q2", PeopleRequired = 50, PeopleAvailable = 45 },
      new Location { Key = "BLR", Quarter = "Q3", PeopleRequired = 25, PeopleAvailable = 28 },
      new Location { Key = "BLR", Quarter = "Q4", PeopleRequired = 60, PeopleAvailable = 58 },
      new Location { Key = "CHN", Quarter = "Q1", PeopleRequired = 77, PeopleAvailable = 92 },
      new Location { Key = "CHN", Quarter = "Q2", PeopleRequired = 42, PeopleAvailable = 66 },
      new Location { Key = "CHN", Quarter = "Q3", PeopleRequired = 29, PeopleAvailable = 20 },
      new Location { Key = "CHN", Quarter = "Q4", PeopleRequired = 22, PeopleAvailable = 24 },
      new Location { Key = "CAD", Quarter = "Q1", PeopleRequired = 100, PeopleAvailable = 150 },
      new Location { Key = "CAD", Quarter = "Q2", PeopleRequired = 200, PeopleAvailable = 250 },
   };

   var results =
   (
      from loc in locations.Select(l => new { l.Key }).Distinct()
      join q1 in locations.Where(l => l.Quarter == "Q1") on loc.Key equals q1.Key into quarter1
      join q2 in locations.Where(l => l.Quarter == "Q2") on loc.Key equals q2.Key into quarter2
      join q3 in locations.Where(l => l.Quarter == "Q3") on loc.Key equals q3.Key into quarter3
      join q4 in locations.Where(l => l.Quarter == "Q4") on loc.Key equals q4.Key into quarter4
      from q1 in quarter1.DefaultIfEmpty()
      from q2 in quarter2.DefaultIfEmpty()
      from q3 in quarter3.DefaultIfEmpty()
      from q4 in quarter4.DefaultIfEmpty()
      select new
      {
         loc.Key,
         Q1_PeopleRequired  = q1 != null ? q1.PeopleRequired  : -1,
         Q1_PeopleAvailable = q1 != null ? q1.PeopleAvailable : -1,
         Q2_PeopleRequired  = q2 != null ? q2.PeopleRequired  : -1,
         Q2_PeopleAvailable = q2 != null ? q2.PeopleAvailable : -1,
         Q3_PeopleRequired  = q3 != null ? q3.PeopleRequired  : -1,
         Q3_PeopleAvailable = q3 != null ? q3.PeopleAvailable : -1,
         Q4_PeopleRequired  = q4 != null ? q4.PeopleRequired  : -1,
         Q4_PeopleAvailable = q4 != null ? q4.PeopleAvailable : -1
      }
   );

   results.Dump();
}

// Define other methods and classes here
public class Location
{
   public string Key          { get; set; }
   public string Quarter      { get; set; }
   public int PeopleRequired  { get; set; }
   public int PeopleAvailable { get; set; }
}

В результате я получил именно то, что искал.Это выше может или не может быть ЛУЧШИМ способом, и я делаю лаг на большом столе, но это работает:)

Key | Q1_PeopleRequired | Q1_PeopleAvailable | Q2_PeopleRequired | Q2_PeopleAvailable | Q3_PeopleRequired | Q3_PeopleAvailable | Q4_PeopleRequired | Q4_PeopleAvailable 
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
BLR | 70                | 35                 | 50                | 45                 | 25                | 28                 | 60                | 58
CHN | 77                | 92                 | 42                | 66                 | 29                | 20                 | 22                | 24
CAD | 100               | 150                | 200               | 250                | -1                | -1                 | -1                | -1
0 голосов
/ 19 января 2012

Я не уверен, что вы пробовали, есть ли необходимость в эффективности или гибкости, или что вам действительно нужно для выходного контейнера, но, возможно, что-то настолько простое, как это полезно.Предполагая, что dt - это ваша дата:

var newSet = dt.AsEnumerable()
               .GroupBy(r => r.Field<string>("Location"))
               .Select(g => new
               {
                    Location = g.Key,
                    ppl_required_Q1 = g.Where(p => p.Field<string>("Quarter") == "Q1").Sum(p => p.Field<int>("ppl_required")),
                    ppl_required_Q2 = g.Where(p => p.Field<string>("Quarter") == "Q2").Sum(p => p.Field<int>("ppl_required")),
                    ppl_required_Q3 = g.Where(p => p.Field<string>("Quarter") == "Q3").Sum(p => p.Field<int>("ppl_required")),
                    ppl_required_Q4 = g.Where(p => p.Field<string>("Quarter") == "Q4").Sum(p => p.Field<int>("ppl_required")),
                    ppl_available_Q1 = g.Where(p => p.Field<string>("Quarter") == "Q1").Sum(p => p.Field<int>("ppl_available")),
                    ppl_available_Q2 = g.Where(p => p.Field<string>("Quarter") == "Q2").Sum(p => p.Field<int>("ppl_available")),
                    ppl_available_Q3 = g.Where(p => p.Field<string>("Quarter") == "Q3").Sum(p => p.Field<int>("ppl_available")),
                    ppl_available_Q4 = g.Where(p => p.Field<string>("Quarter") == "Q4").Sum(p => p.Field<int>("ppl_available")),
                });

EDIT

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

public static DataTable ToDataTable<T>(this IEnumerable<T> source, string newTableName)
{
    DataTable newTable = new DataTable(newTableName);

    T firstRow = source.FirstOrDefault();
    if (firstRow != null)
    {
        PropertyInfo[] properties = firstRow.GetType().GetProperties();
        foreach (PropertyInfo prop in properties)
        {
            newTable.Columns.Add(prop.Name, prop.PropertyType);
        }

        foreach (T element in source)
        {
            DataRow newRow = newTable.NewRow();
            foreach (PropertyInfo prop in properties)
            {
                newRow[prop.Name] = prop.GetValue(element, null);
            }
            newTable.Rows.Add(newRow);
        }
    }
    return newTable;
}
...