質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.84%

  • C#

    6262questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

c#で連想配列の多次元配列は使わないのでしょうか

解決済

回答 6

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 383

odmdom

score 70

PHPからC#に移行してきました。

c#でDictionalyを使ってPHPでいう下記のような連想配列をつくって1つの配列で複数の言語データを管理しようとしています。

しかしC#の記事で連想配列の多次元データを扱うことは絶対にないという記事を見つけ混乱しています。
C#ではどのように実装するのが好ましいのでしょうか。

見つけた記事URLです
https://anond.hatelabo.jp/20170524202057

PHPで書くと下記の処理をC#で実装したいです

$data_arr['ja']['fruit'] = array(
                        'apple' => 'りんご',
                        'banana' => 'ばなな',
                        'grape' => 'ぶどう',
);

$data_arr['en']['fruit'] = array(
                        'apple' => 'apple',
                        'banana' => 'banana',
                        'grape' => 'grape',
);

//日本語で使用
$lang = 'ja' //実際は使用言語を動的に取得
$btn1 = $data_arr[$lang]['fruit']['apple'];

?>

追記1

頂いた意見を参考に下記の形で実装しようと試みましたが、変なところで躓いてしましました。
下記クラスをnewしたときに各言語テキストをセットし、GetList()で取得という処理を行いのですが、switchのreturn data箇所でコンテキストが存在しませんというエラーがでてしまいます。
また、取得する側のコードのvar textdata2 = new TextData2("fruit");の箇所では下記画像のようなエラーがでてしまいますが原因が分からない状況です。

イメージ説明

  public class Fruit
    {
        public string lang { get; set; }
        public string apple { get; set; }
        public string banana { get; set; }
        public string grape { get; set; }
    }


    public class TextData2
    {

        public List<Fruit> fruit_list;

        public void Main(string page)
        {
            switch (page)
            {
                case "fruit":
                    fruit_list = new List<Fruit>()
                    {
                        new Fruit(){lang = "ja", apple = "りんご", banana = "ばなな", grape="ぶどう"},
                        new Fruit(){lang = "en", apple = "apple", banana = "banana", grape="grape"},
                    };
                    break;


            }
        }

        public dynamic GetList(string lang, string page)
        {
            switch (page)
            {
                case "fruit":
                    var data = (from l in fruit_list
                                where l.lang == lang
                                select l).FirstOrDefault();
                    break;

            }

            return data;
        }
    }

下記は取得側のコード

            //取得側
            var textdata2 = new TextData2("fruit");
            var fruit_list = textdata2.GetList(lang, "fruit");
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 6

+8

絶対にないということはありません。
その人の個人的な意見です。

ただ、PHP と C# ではコーディングスタイルが違います。
PHP 流のコーディングスタイルを使って C# プログラミングすると違和感のある読みにくいソースになります。
おそらくそのことを言っているのだろうと思います。

たとえば質問のような状況の場合、C# ならばデータにボタンを含めるのではなく、ボタンにデータをバインドします。
また多言語化の方法も違います。
結果的にデータの階層が浅くなって多次元 Dictionary が不要になります。

そのような C# らしいスタイルを学ぶには、「C# で多次元配列を作る方法」を学ぶのではなく、「C# で多言語化する方法」「C# でボタンとデータを結びつける方法」を学ぶように、頭を切り替える必要があります。

妥協して元の方法にちょっと C# らしさを与えるなら次のようになります。

using System;
using System.Linq;
using System.Globalization;
using System.Windows.Forms;
using System.Collections.Generic;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var button1 = new Button();
            var button2 = new Button();
            var button3 = new Button();

            var data = new List<Datum>
            {
                new Datum(new CultureInfo(1041), Kind.Fruit, button1, "りんご"),
                new Datum(new CultureInfo(1041), Kind.Fruit, button2, "ばなな"),
                new Datum(new CultureInfo(1041), Kind.Fruit, button3, "ぶどう"),
                new Datum(new CultureInfo(1033), Kind.Fruit, button1, "apple"),
                new Datum(new CultureInfo(1033), Kind.Fruit, button2, "banana"),
                new Datum(new CultureInfo(1033), Kind.Fruit, button3, "grape"),
            };

            var text = data
                .Where(a => a.Culture.LCID == 1041 && a.Kind == Kind.Fruit && a.Button == button1)
                .FirstOrDefault()?.Text;
            Console.WriteLine(text ?? "みつかりませんでした");
        }
    }

    public enum Kind
    {
        Fruit, Animal, Vehicle
    }

    public class Datum
    {
        public Datum(CultureInfo culture, Kind kind, Button button, string text)
        {
            Culture = culture;
            Kind = kind;
            Button = button;
            Text = text;
        }
        public CultureInfo Culture { get; set; }
        public Kind Kind { get; set; }
        public Button Button { get; set; }
        public string Text { get; set; }
    }
}

コード量が爆発的に増えて、「なぜこのようなことをしなければならないのか」とお思いかもしれません。
しかし、enum や class は別ファイルで提供しますし、データの読み込みはデータベースなどで与えるもの、Button の作成はデザイナーを使うものですから、実際にはそれほどのことはありません。

増えたコードには、保守性を高める役目があります。
このようなその場限りのコードではなく、大規模なプログラミングをするときには力を発揮しますし、かえってコード量が減ることもあります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/14 11:36

    もちろん、その場限りの簡単なコードなら、ここまでしなくても <Dictionary, <Dictionary, <Dictionary, ... を使うのもありです。

    キャンセル

  • 2018/05/14 13:35

    ありがとうございます。
    btnという記述が誤解を生んでいる気がしましたのでコードを書き直しました。

    実際の処理としては最初の画面でユーザーが言語選択をボタンで選択し、このとき日本語(ja)が選ばれれば次のページ(fruit選択ページ)で日本語テキストのボタンを表示させます。
    このとき、多次元連想配列を用意しておけば言語と選択項目を表すfruitを指定すればあとはループでバインドさせてボタンのテキストを書き換えできるはずです。

    そして最後のページでは、選択した内容を「日本語」+「選択した言語」で表示させる必要があるため、選択した内容をkey(この場合はappleやbanana)で持っておけば、あとからどの言語を呼び出す場合でも多次元連想配列から容易に取得できると考えました。

    この構造はおかしいでしょうか。

    多言語化の方法が別にあることは理解しましたが、そこはまた別の話として多次元連想配列からデータを取得するという構造に問題があるのであれば、どのように実装するのが一般的なのかが知りたいかったのですが、Dictionaryで多次元連想配列を生成することが特に問題なければその方法で実装しようと思います。

    キャンセル

  • 2018/05/14 14:02

    ローカルアプリであろうと Web アプリであろうと、アプリケーションのインストール時点もしくは開始時点で言語を選択させ、以降は設定が変更されるまでそれを使うのが通常です。
    画面毎に言語を選択させたり、多言語のリソースをすべてオンメモリに持つようなことはあまりしません。
    また選択肢が果物しかないなら fruit キーは必要ありません。

    動けば勝ちという考え方もありますので、オブジェクト指向に慣れていないならとりあえずそれでやってみればいいのではないかと思います。
    多階層 Dictionary を使ってはいけないというのは、使ったらまずいのではなく、ちゃんと設計すれば使うような状況があまりないということにすぎませんから。

    キャンセル

  • 2018/05/14 14:49

    fruit以外のページもあるのでそこは大丈夫です。
    PHPでは多次元連想配列を頻繁に使うので、c#の正しい設計や構造というものがまだはっきりとはわかっていませんが、リソースの件はその通りと思いますので使用言語によって分岐をかけてから配列生成する形にしてみようかと思います。

    キャンセル

checkベストアンサー

+5

「絶対ない」というのは意味不明ですが、質問者さんが例に挙げた多言語化の話なら、リソースをつかうので質問者さんが書いたソースのようなことは普通はしません。

【追伸】

PHP とのことですから Web アプリの話、C# に移行ということは ASP.NET の話と想像していますが(想像が違っていたら以下はスルーしてください)・・・

ASP.NET Web アプリでどのようにリソースを使って多言語するかの例を書いた記事をご参考に紹介します。

aspx ページでのリソースの利用
http://surferonwww.info/BlogEngine/post/2015/04/21/use-of-resources-in-aspx-page.aspx

【追記】

2018/05/14 12:46 のコメントで「回答欄に案を書いておきます」と書きましたがそれを以下に書きます。あくまで「案」で、実際の目的によってはもっと適切な方法があるかもしれません。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;

namespace ConsoleApplication4
{
    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Dictionary<int, Person> data = new Dictionary<int, Person>();
            data.Add(1000, new Person() { Name = "山田太郎", Age = 27 });
            data.Add(1001, new Person() { Name = "佐藤次郎", Age = 30 });

            foreach (KeyValuePair<int, Person> kvp in data)
            {
                Console.WriteLine("Key = {0}, Name = {1}, Age = {2}",
                    kvp.Key, kvp.Value.Name, kvp.Value.Age);
            }

            // 結果は:
            // Key = 1000, Name = 山田太郎, Age = 27
            // Key = 1001, Name = 佐藤次郎, Age = 30
        }
    }
}

【追記2】 

2018/05/14 15:21 のコメントで、

ID が各ユーザーに固有のもの(DB で言うと主キーのようなもの)であれば、Person に含め、Linq などを使って取得する方がすっきりしてますし、今時のやり方として自分的にはお勧めです。後でサンプルを回答欄に追記しておきます。

・・・と書きましたがそれを以下に書きます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;

namespace ConsoleApplication4
{
    public class Person2
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<Person2> data2 = new List<Person2>() {
                new Person2() { ID = 1000, Name = "山田太郎", Age = 27 },
                new Person2() { ID = 1001, Name = "佐藤次郎", Age = 30 }
            };

            var person = (from p in data2
                          where p.ID == 1000
                          select p).FirstOrDefault();

            Console.WriteLine("ID = {0}, Name = {1}, Age = {2}", 
                person.ID, person.Name, person.Age);

            // 結果は:
            // ID = 1000, Name = 山田太郎, Age = 27
        }
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/14 10:39

    移行という書き方が悪かったですね。単にPHPを最初に学び、新たにC#を学習しているという意味です。
    WebアプリではなくスマホアプリをC#で作成しようとしています。

    リソースについては確かにそうかもしれません。
    ではC#でどのように実現するのがよくわかりません。

    キャンセル

  • 2018/05/14 11:04 編集

    > ではC#でどのように実現するのがよくわかりません。

    質問に書いてある例では自分は多言語化の話しか想像できないので、多言語化以外のことで「どのように実現」という話をするのは難しいです。

    多言語化の他に PHP での連想配列の作り方・使い方の具体例を出してもらって、それを C# で実装するにどうするかという話をしていただければ、何か案が出てくるかもしれません(出てこなかったらスミマセンが)。

    キャンセル

  • 2018/05/14 11:28

    ぱっと思いついた例で申し訳ないのですが、仮に下記のようなデータをハードコーディングする場合にDictionaryで連想配列にして管理しようとしたのですが、URLのような記述を見かけ質問させていただいた次第です。


    <?php
    $data[1000] = array(
    'name' => '山田太郎',
    'age' => 27,
    );

    $data[1001] = array(
    'name' => '佐藤次郎',
    'age' => 30,
    );


    //使用:IDが1000のnameを取得
    $ID = 1000; //実際は動的に取得
    $name = $data[$ID]['name']; //山田太郎


    ?>

    キャンセル

  • 2018/05/14 12:46

    回答欄に案を書いておきます。

    キャンセル

  • 2018/05/14 13:44

    なるほど。そういう書き方ができるのですね!
    私が知りたかった答えをいただけた気がします。

    一度この方法で書いてみたいと思います。

    キャンセル

  • 2018/05/14 14:03

    ID が各ユーザーに固有のもの(DB で言うと主キーのようなもの)であれば、ID は Person クラスに含めて、上の私の回答の例で書いたような Dictionary は使わない方がすっきりするかもしれません。合わせて検討ください。

    キャンセル

  • 2018/05/14 14:52

    あとでIDを基にデータを呼びたい場合には、書いていただいた方法で良いように感じますがいかがでしょうか。

    キャンセル

  • 2018/05/14 15:21

    ID が各ユーザーに固有のもの(DB で言うと主キーのようなもの)であれば、Person に含め、Linq などを使って取得する方がすっきりしてますし、今時のやり方として自分的にはお勧めです。後でサンプルを回答欄に追記しておきます。

    キャンセル

  • 2018/05/14 15:23

    ご丁寧な回答をいただきありがとうございます。
    参考にさせていただきます。

    キャンセル

  • 2018/05/14 15:37

    追記拝見しました。そのような書き方もできてしまうのですね。
    私も一目みて気に入ったのでLINQを使ったやり方で実装できるかやってみたいとおもいます。

    また、ここまでで私が求めていた回答をくださったSurferOnWww様をベストアンサーとさせていただきたいと思います。

    いろいろと勉強になりました。ありがとうございます。
    実装ができたあとで解決方法を記載したいと思います。

    キャンセル

  • 2018/05/14 18:36

    すみません、実際に書いてみたのですが躓いてしまっております。
    質問に追記しましたので、ご意見いただけませんでしょうか。
    また、この実装方法がおかしい場合はご助言いただけますと助かります。

    キャンセル

+5

結論から言ってしまえば、 そんなことはありません 
データ構造によっては多次元連想配列は必要になりますし、その場合には(結果的には)多重の Dictionary を使用する形になります。

ただ、まずはそのような構造になるデータ構造自体を見直そう、とはいえます。
C# では型を正しく宣言しなくてはなりません。PHP のように「思い立ったから多次元連想配列でやっちゃえ」とはいかないわけです。ですからきちんとデータ構造を考えて処理しましょう、という話です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/14 10:44

    ご回答ありがとうございます。

    まだよくわかっていないのですが、多次元連想配列にするにしても明確に型を指定してやればいいというわけではないのでしょうか?
    PHPでは質問のような書き方ができるのでデータの管理が1つの変数でできるのでわかりやすいのですが、C#ではどのように値を持たせるべきなのかが分かりません。

    キャンセル

  • 2018/05/14 10:54

    だから、そこが「データ構造をきちんと考えましょう」という意味です。明確に型を指定してやるということは、イコール明確なデータ構造を提示することです。
    この例で言えば、本質的には多言語化であればこのような記述自体が要りません。多言語化にはこれとは別の(標準化された)方法があるので、何も自分でイチから実装する必要はありません。車輪を再発明しても意味は薄いのです。

    キャンセル

+5

直接の回答ではないのですが、情報の探し方について。

検索するとき、情報源の内容の確からしさを気にするといいと思います。
誰が書いたか、いつ書かれたものか、どのような状況でかかれたものか、など。

上記に照らし合わせたとき、例えば例示されましたはてなAnonymous Diaryの記事などは、誰が書いたかも分からない、どのような事例かの記載も無い記事ですので、情報の確実性は落ちます。
このような内容は、眉に唾して臨むべきかと思います。
古来より曰く「嘘を嘘と見抜けないものにインターネットは難しい」というやつです。

ポエムでした。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+4

PHP は型付け制約がゆるい、動的型付け言語であるのにたいして、
C# は型付け制約の強い静的型付け言語です。
静的型付け言語では、全く同じように扱えるものしか同じ型にしないのが原則です。
例題では'btn1'と'りんご'は明らかに違う性質を持ったものですから、同じstring型として扱うのは避けるのが賢明です。

違う用途のものを同じ配列に入れると面倒なので、連想配列だけではなく多次元配列を使うことも稀です。
またC#には便利なコレクションが沢山あるので、配列を使うこと自体が多くはありません。
結果として、科学や技術系の計算などで大量の数値を扱う場合を除いて多次元配列の出番はなくなるのです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/14 11:37

    btn1はあくまでデータを取得する際のkeyとして利用したいだけなのでstring型を指定しますが、string型だとおかしいのですか?
    連想配列だけではなく多次元配列を使うことも稀ということであれば、質問の処理をC#ではどのようにデータを持たせ、どのように取得すべきでしょうか。。

    キャンセル

  • 2018/05/14 11:52

    Zuishinさんがとてもいい回答をしてますので、参考にしてください。

    キャンセル

+4

こんにちは。

そのリンク先の人が「絶対にない」と書いている方法を使えば可能です。あまり見かけないのは事実ですが、必要なら使っても問題ない方法と思います。
(C#に不慣れな段階でそのような記載を見かけたのならば、他の人の意見を聞くのは良いことと思います。)

しかし、多言語化対応をハードコーディングするのはあまり好ましい方法ではないと思います。
多言語化の手法は大きく2つの流れがあると思います。マイクロソフト方式gettext方式です。

個人的にはgettext方式が好きですね。マイクロソフト方式は複数の仕組みがあるし、他のOSで使えない(使いづらい?)ので。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/14 10:49

    ご回答ありがとうございます。
    多言語化の方法をご提示いただいたのはありがたいのですが、私が知りたいのは多言語化の方法ではなく、まさしくハードコーディングする場合のデータの持たせ方です。
    よい方法をご存じであれば教えていただけますと助かります。

    キャンセル

  • 2018/05/14 11:21

    「そのリンク先の人が「絶対にない」と書いている方法」で十分と思いますよ。

    キャンセル

  • 2018/05/14 11:30

    なるほど。ありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.84%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C#

    6262questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。