

フルーツの分配プログラムを作っています。

リストの扱い方、リスト内の要素によるリストのソートの仕方が不明です。それができたら、リスト内の各アイテムにループによって、任意の数を一つずつ振り当てていくということがしたいです。

  * リストは、人名と年齢についての情報が入っています(氏 + 名 + 年齢)で、ユーザー入力によりリスト追加されます。（氏名と年齢にわけて多次元配列にしたほうがスマートなのでしょうか？）
  * リストを年齢でソートしたいです
  * 任意の入力数を、リスト内の情報に順番に加えていきたいです。(割り算による同じ数の分配ではなく、ループでフルーツがなくなるまで一つずつ順番に分配するイメージ)

### コード

[code]

    List<string> names = new List<string>();    
    private void BtnDivide_Click(object sender, RoutedEventArgs e)
    {
        int nrOfFruits = int.Parse(TxtTotalFruits.Text);
        int c = names.Count;
        int division;
        string firstName = TxtFirstName.Text;
        string lastName = TxtLastName.Text;      
        string txtAge = TxtAge.Text;           
    
        // 割り算で平等に分配すると場合により余剰がでるので、最終的には商を出すのではなく、ループで最後の一つまで分配したいです。
    
        division = nrOfFruits / c;
    
        for (int i = 0; i < c; i++)
        {
            // リスト内の年齢の要素を使って昇順にソートしたいです。
    
            //Lambda operator: => 
    
            //OrderByを使う？
            var orderedNames = names.OrderBy(txtAge => names);
    
            //wpf上のリストボックスNameListとorderedNamesを繋ぐ
            NameList.Items[i] = orderedNames;
    
            //希望の順番でリストをソートできたところで、wpf上のリストボックスに数を表示させる。
    
            NameList.Items[i] += " " + division.ToString() + " 個のフルーツ";
        }
    }
    
[/code]


CC BY-SA 4.0
2018-12-21T08:02:33.443
51417
2019-01-25T06:37:28.657
2018-12-21T19:37:38.963
754
31225
question
c#
リストの要素によるソート(OrderBy)と、任意の数の割り当てについて


> 氏名と年齢にわけて多次元配列にしたほうがスマートなのでしょうか？

データ構造は、アクセスしやすいようにクラスや構造体で定義したほうが良いです。

[code]

        public class Person
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public int Age { get; set; }
            public int Fruits { get; set; }
        }
    
[/code]

OrderByの引数は、要素からソートで使うキーを抽出する関数を指定します。下記の例ではラムダ式で記述しています。

[code]

        private void SortAndDistributeFruits(List<Person> persons, int fruits)
        {
            // 年齢でソート
            var orderedPersons = persons.OrderBy(e => e.Age).ToList();
    
            // ループでフルーツがなくなるまで一つずつ順番に分配する
            for (int i=0; i<fruits; i++)
            {
                // 人数で割った余りで誰に配るかを決める
                var index = i % orderedPersons.Count;
    
                // 1つ配る
                orderedPersons[index].Fruits++;
            }
        }
    
[/code]

OederByより返されるリストは元のリストとは別なものです。もし元のリスト自体の並び順を変えたいのなら`Sort`メソッドを使用する方法もあります。


CC BY-SA 4.0
2018-12-23T16:57:54.273
51464
2019-01-25T06:37:28.657
2019-01-25T06:37:28.657
14817
14817
51417
answer


それぞれの項目について、順番に片付けていきましょう。

まず最初の条件から。リストアイテムが何を持っていて、利用者にリストをどのように表示したいのか、一旦整理してみましょう。  
今回はリストが人物の一覧をを持っていて、それぞれのリストアイテムに

  * 年齢
  * 苗字
  * 名前
  * フルーツの個数

を持たせたいとお見受けしました。  
データの持ち方としては、これらをクラスや構造体として管理できるようにするとスマートです。

2つめです。リストのソートをするときに `OrderBy`
を使いたい場合、引数にはソートするためのキーを得るためのラムダ式を指定します。リストの中の全ての要素を与えられたラムダ式で変換して、その結果でソートしてあげるというイメージです。ただし、これは元のリストをソートした
**結果を返している** のであって、元のリスト **そのものをソートしているわけではありません** 。もしリストそのものをソートしてあげたいときは、
`List<T>` クラスであれば `Sort` というメソッドがあります。

そして3つ目のフルーツの分配について。今回はフルーツの種類については問わず、単純に個数をなるべく均したいということでした。そして、余った分は年少の人から順に配っていくとのことでしたね。  
そうであれば、

[code]

    // 全員に等しく配るフルーツの数。C#の仕様だと、整数同士で割ると結果の小数部分は切り捨てられます。
    var fruitsDiv = nrOfFruits / peopleList.Count;
    // 余ったフルーツの数、つまりフルーツを1つ多くもらえる人の数です。
    var fruitsMod = nrOfFruits % peopleList.Count;
    
    // peopleListは年齢が若い順に並び替えられた人物のリストです。
    // FruitsCountというフルーツの数を覚えるためのプロパティを持っているとします。
    for(var i = 0; i < peopleList.Count; i++)
    {
        // 年少の人からfruitsMod人だけフルーツをfruitsDiv個と、さらにひとつ多く配ります。
        if (i < fruitsMod)
        {
            peopleList[i].FruitsCount = fruitsDiv + 1;
        }
        else
        {
            peopleList[i].FruitsCount = fruitsDiv;
        }
    }
    
[/code]

といった風にしてあげるとよいでしょう。

ちなみに、 `orderedNames` の部分が `System.Linq.OrderedEnumerable...`
となってしまうのは、`orderedNames` が暗黙的に文字列に変換されてしまっているからですね。既定では渡したオブジェクトが持っている  
`ToString` というメソッドが返す値がそこに入ります。自分でクラスを作ったときに `ToString`
を拡張してあげると、この変換結果を自由に書き換えることができます。簡単なリスト表示であればテンプレートを作ることなくこれで済んでしまうことがあるかもしれません。より複雑な表示の制御がしたい場合はWPFのテンプレートについて詳しく調べるか、改めて別の質問をされた方がよい結果が得られると思います。


CC BY-SA 4.0
2018-12-24T10:43:00.177
51479
2018-12-24T10:56:18.077
2018-12-24T10:56:18.077
13887
13887
51417
answer