5

IEnumerable があり、次のビジネス ロジックを使用してデータを 3 つの列に分割したいと考えていました。アイテムが 3 つ以下の場合、列ごとに 1 つのアイテム、それ以外の場合は、アイテムの合計を 3 で割りたい場合は、残りのアイテム (1 つまたは 2 つのアイテム) を最初の 2 つの列の間で分割します。これはかなり醜いですが、仕事はします。linq をもう少し有効に活用したり、場合によっては switch ステートメントを削除したりするためのヒントを探しています。コードを改善するためのアドバイスやヒントをいただければ幸いです。

var numItems = items.Count;

            IEnumerable<JToken> col1Items,
                                col2Items, 
                                col3Items;


            if(numItems <=3)
            {
                col1Items = items.Take(1);
                col2Items = items.Skip(1).Take(1);
                col3Items = items.Skip(2).Take(1);

            } else {

                int remainder = numItems % 3,
                    take = numItems / 3,
                    col1Take, 
                    col2Take, 
                    col3Take;

                switch(remainder)
                {
                    case 1:
                        col1Take = take + 1;
                        col2Take = take;
                        col3Take = take;
                        break;
                    case 2:
                        col1Take = take + 1;
                        col2Take = take + 1;
                        col3Take = take;
                        break;
                    default:
                        col1Take = take;
                        col2Take = take;
                        col3Take = take;
                        break;

                }

                col1Items = items.Take(col1Take);
                col2Items = items.Skip(col1Take).Take(col2Take);
                col3Items = items.Skip(col1Take + col2Take).Take(col3Take);

最終的に、私はこれらをmvc Razorビューで使用しています

<div class="widgetColumn">
                @Html.DisplayFor(m => col1Items, "MenuColumn")                       
            </div> 

            <div class="widgetColumn">
                @Html.DisplayFor(m => col2Items, "MenuColumn")                       
            </div> 

            <div class="widgetColumn">
                @Html.DisplayFor(m => col3Items, "MenuColumn")                       
            </div>  

私の最初の試みでは、colNItems 変数と colNTake 変数を取り除きたいのですが、同じように機能させるための正しいアルゴリズムがわかりません。

for (int i = 1; i <= 3; i++ )
            {
                IEnumerable<JToken> widgets = new List<JToken>();
                var col = i;
                switch(col)
                {
                    case 1:
                       break;
                    case 2:
                        break;
                    case 3:
                        break;
                }
            }
4

9 に答える 9

6

列は固定幅ですか? もしそうなら、コレクションに対して特別なことをする必要はありません。ブラウザに頼ってください。3 列の全体幅を持つ外側のコンテナーを用意し、各項目の div を入力します (左にフロートします)。内側のコンテナの幅が外側のコンテナのちょうど 1/3 になるように設定します。

ここに簡単なフィドルがあります

スタイルの簡単なヒントはこちら

div#outer{
    width:300px;    
}

div#outer > div{
    width:100px;
    float:left;    
}
于 2013-08-01T15:57:46.157 に答える
1

のようなことはできませんか?

int len = numItems / 3;
int rem = numItems % 3;

int col1Take = len + (rem > 0 ? 1 : 0);
int col2Take = len + (rem > 1 ? 1 : 0);
int col3Take = len;

編集:

任意の数の列 ( COLUMNS) に対して機能する、より一般的なソリューションは次のようになります。

int len = numItems / COLUMNS;
int rem = numItems % COLUMNS;

foreach (var i in Enumerable.Range(0, COLUMNS)) {
  colTake[i] = len + (rem > i ? 1 : 0);
}
于 2013-08-01T15:47:12.717 に答える
1

一般化できます:

int cols = 3;
IEnumerable<JToken> colItems[3]; // you can make this dynamic of course

int rem = numItems % cols;
int len = numItems / cols;

for (int col=0; col<cols; col++){
    int colTake = len;
    if (col < rem) colTake++;
    colItems[col] = items.Skip(col*len).Take(colTake);
}

テストしていませんが、これは任意の数の列で機能するはずです。

また、変数 col1、col2、col3 が必要なときはいつでも、col[0]、col[1]、col[2] を考えてください。

于 2013-08-01T16:17:07.940 に答える
0

列をラウンドロビンで埋めたい場合は、次を使用できます。

int numColumns = 3;

var result = Enumerable.Range(1,numColumns).Select(c =>
      items.Where((x,ix) => ix % numColumns == c-1).ToArray()
   );
于 2013-08-01T15:55:31.047 に答える
0

LinqLib (nuget: LinqExtLibrary) には、それを行う ToArray() のオーバーロードがあります。

using System.Collections.Generic;
using System.Linq;
using LinqLib.Array;

...

    public void TakeEm(IEnumerable<int> data)
    {
        var dataAry = data as int[] ?? data.ToArray();
        var rows = (dataAry.Length/3) + 1;
        //var columns = Enumerable.Empty<int>().ToArray(3, rows);
        // vvv These two lines are the ones that re-arrange your array
        var columns = dataAry.ToArray(3, rows);
        var menus = columns.Slice();
    }
于 2013-08-01T16:53:25.013 に答える
0

これは高速ではありませんが、うまくいきます:

var col1Items = items.Select((obj, index) => new { Value = obj, Index = index })
    .Where(o => o.Index % 3 == 0).Select(o => o.Value);
var col2Items = items.Select((obj, index) => new { Value = obj, Index = index })
    .Where(o => o.Index % 3 == 1).Select(o => o.Value);
var col3Items = items.Select((obj, index) => new { Value = obj, Index = index })
    .Where(o => o.Index % 3 == 2).Select(o => o.Value);

これは、インデックス パラメータを含む Select のバージョンを使用します。GroupBy を使用すると、数行のコードを犠牲にしてこれを少し高速化できます。

于 2013-08-01T16:01:11.620 に答える
0

それは役立つかもしれません

        IEnumerable<object> items = new Object[]{ "1", "2", "3", "4", "5", "6", "7","8", "9", "10", "11", "12","13", "14" };

        IEnumerable<object> col1Items = new List<object>(),
                            col2Items = new List<object>(), 
                            col3Items = new List<object>();

        Object[] list = new Object[]{col1Items, col2Items, col3Items};
        int limit = items.Count()/3;
        int len = items.Count();
        int col;            

        for (int i = 0; i < items.Count(); i++ )
        {                
            if (len == 3) col = i;
            else col = i / limit;

            if (col >= 3) col = i%limit ;

            ((IList<object>)(list[col])).Add( items.ElementAt(i));

        }
于 2013-08-01T16:00:33.317 に答える