2013-07-02 6 views
0

У меня есть список каждый объект, содержащий строку xvalue:Tally Значения каждого столбца

Object.xvalue = "112" 
Object.xvalue = "332" 
Object.xvalue = "213" 

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

Объект № 1: (1,3,2)

int var1 = 1 
int var2 = 1 
int var3 = 1 

Объект # 2: (1,3,1)

int var1 = 2 
int var2 = 0 
int var3 = 1 

Объект № 3: (2,2,3)

int var1 = 0 
    int var2 = 2 
    int var3 = 1 

Это то, что я мог бы сделать с помощью LINQ?
Если бы кто-то не мог дать некоторые указания для этого?

+1

Не могли бы вы подробнее рассказать о том, как получить «var1 = 2, var2 = 1, var3 = 0' из строки« 132 »? – Vlad

+2

По столбцу вы имеете в виду каждую позицию в строке? То есть столбец 1 будет 'Object.xvalue [0]' column 2 будет 'Object.xvalue [1]' и столбец 3 'Object.xvalue [2]'? Я не совсем понимаю вопрос – konkked

+0

Это правильно по столбцу, я имею в виду положение в строке. Я хочу знать, сколько у них 1, сколько их 2, и сколько у них 3 для каждого столбца. – Baxter

ответ

5

Я предполагаю, что вы хотите следующее:

var counts = list.Select(s => new 
       { 
        var1 = s.Count(c => c == '1'), 
        var2 = s.Count(c => c == '2'), 
        var3 = s.Count(c => c == '3') 
       }); 

Для решения масштабируемой для обнаружения всех возможных значений, то возможно, нужно что-то вроде этого:

var counts = list.Select(s => s.GroupBy(c => c) 
           .ToDictionary(g => g.Key, g => g.Count())); 

Это сосчитать все символы строки.

+0

Хотя этот код может решить текущую проблему .... но это решение вообще не масштабируется .. что, если OP хочет подсчитать символы: 4,5,6,7,8,9,0, a, b, c, d и т. д. – nemesv

+0

@nemesv: OP явно запросил немасштабируемое решение: наличие _variables_ 'var1',' var2', 'var3' довольно нескромно, не так ли? – Vlad

+0

@nemesv: И у меня нет назначений в 'Select', он создает экземпляр [анонимного класса] (http://msdn.microsoft.com/en-us/library/vstudio/bb397696.aspx). – Vlad

2
var input = "112"; 

var result = input 
      .GroupBy(c => c).Select(g => new {Key = g.Key, Count = g.Count()}); 

После этого вы можете делать что-либо со значениями и назначать их любой переменной.

+0

вам действительно не нужны 'ToCharArray' и' ToList', поскольку строка является 'IEnumerable ' самой. – Vlad

+0

Правда, спасибо :) –

0

ОК, поэтому я не понял вопрос правильно, поэтому мой первый ответ был немного неактуальным, вот моя вторая попытка, я решил не делать все в linq, потому что это может очень запутать очень быстро, вот версия, которая позволяет любые типы символов и дает подсчеты для всех столбцов.

private class Example 
    { 
     public string xvalue { get; set; } 
    } 

    //this will give you matches per column for any amount of chars 
    public static Dictionary<char, int[]> GetCount(IEnumerable<Example> matchAgainst,params char[] matches) 
    { 

     //maybe there is an easier way to do this in linq I am not sure 
     List<string> flattenedColumns = new List<string>(); 
     foreach (var target in matchAgainst) 
     { 
      for (int i = 0 ; i < target.xvalue.Length ; i++) 
      { 
       if (flattenedColumns.Count <= i) 
       { 
        flattenedColumns.Add (string.Empty); 
       } 
       flattenedColumns [ i ] += target.xvalue [ i ]; 
      } 
     } 

     //now compose based on the chars 
     return (from c in matches 
       select new 
        { 
         CharTarget = c , 
         Counts = (from col in flattenedColumns 
            select col.Count ((ch) => ch == c)).ToArray () 
        }).ToDictionary (rslt => rslt.CharTarget , rslt => rslt.Counts); 
    } 

    public static void Do () 
    { 
     string curr = ""; 
     List<Example> exampleList = new List<Example> (); 
     for(int i=0;i<10;i++) 
      for(int j=0;j<10;j++) 
       for (int k = 0 ; k < 10 ; k++) 
       { 
        curr= i+""+j+""+k; 
        exampleList.Add (new Example { xvalue = curr }); 
       } 

     var matches = GetCount (exampleList , '1' , '2' , '3'); 
     var var1Col1 = matches [ '1' ] [ 0 ]; 
     var var2Col1 = matches [ '2' ] [ 0 ]; 
     //... 
    } 

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

И это более общий вариант, где я предполагаю, что столбцы просто массивы объекта, чтобы выровнять столбцы Я просто использовать агрегат и приватно определенный класс, который представляет собой, если объект был превращен в

private class Row 
{ 
    public object[] Columns {get;set;} 
} 

public static Dictionary<object, int[]> GetCountByIndex(IEnumerable<Row> matchAgainst, params object[] matches) 
{ 
    bool firstTime = true; 
    return 
    (from key in matches 
     let flatCols = (from Row row in matchAgainst select row.Columns).Aggregate ((a , b) => 
     { 
      var retlen = a.Length; 

      if (b.Length > a.Length) 
       retlen = b.Length; 

      object [ ] retv = new object [ retlen ]; 
      //use bool flag to determine first time objects are being aggregated 
      if (!firstTime) 
      { 
       //do every other join 
       for (int i = 0 ; i < retlen ; i++) 
       { 
        List<object> curr = null; 
        if (i >= a.Length) 
        { 
         curr = new List<object> (); 
        } 
        else 
        { 
         curr = a [ i ] as List<object>; 
        } 
        if (i < b.Length) 
        { 
         curr.Add (b [ i ]); 
        } 
        retv [ i ] = curr; 
       } 

      } 
      else 
      { 
       //intialization 
       for (int i = 0 ; i < retlen ; i++) 
       { 
        List<object> curr = new List<object>(); 
        if (i < a.Length) 
        { 
         curr.Add (a [ i ]); 
        } 
        if (i < b.Length) 
        { 
         curr.Add (b [ i ]); 
        } 
        retv [ i ] = curr; 
       } 
       firstTime = false; 

      } 
      return retv; 
     }) 
     select new 
     { 
      Key = key , 
      Value = (from object obj in flatCols 
        select ((List<object>) obj).Count (c => key.Equals (c))).ToArray () 

     }).ToDictionary (keySel => keySel.Key , valSel => valSel.Value); 
} 
Смежные вопросы