每列的计数值

时间:2013-07-02 15:16:57

标签: c# string linq

我有一个List,每个Object包含一个字符串xvalue:

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做的事情吗? 如果没有,有人可以提供一些指示来完成这个吗?

3 个答案:

答案 0 :(得分: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()));

这会计算字符串中的所有字符。

答案 1 :(得分:2)

var input = "112";

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

在此之后,您可以对值执行任何操作,并将它们分配给您想要的任何变量。

答案 2 :(得分: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 );
}