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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C#

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

Q&A

解決済

6回答

5728閲覧

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

Anon_

総合スコア334

C#

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

1グッド

2クリップ

投稿2018/05/14 00:57

編集2018/05/14 23:29

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

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

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

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

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

PHP

1$data_arr['ja']['fruit'] = array( 2 'apple' => 'りんご', 3 'banana' => 'ばなな', 4 'grape' => 'ぶどう', 5); 6 7$data_arr['en']['fruit'] = array( 8 'apple' => 'apple', 9 'banana' => 'banana', 10 'grape' => 'grape', 11); 12 13//日本語で使用 14$lang = 'ja' //実際は使用言語を動的に取得 15$btn1 = $data_arr[$lang]['fruit']['apple']; 16 17?>

追記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");
ssmxgo👍を押しています

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答6

0

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

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

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

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

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

C#

1using System; 2using System.Linq; 3using System.Globalization; 4using System.Windows.Forms; 5using System.Collections.Generic; 6 7namespace ConsoleApp1 8{ 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 var button1 = new Button(); 14 var button2 = new Button(); 15 var button3 = new Button(); 16 17 var data = new List<Datum> 18 { 19 new Datum(new CultureInfo(1041), Kind.Fruit, button1, "りんご"), 20 new Datum(new CultureInfo(1041), Kind.Fruit, button2, "ばなな"), 21 new Datum(new CultureInfo(1041), Kind.Fruit, button3, "ぶどう"), 22 new Datum(new CultureInfo(1033), Kind.Fruit, button1, "apple"), 23 new Datum(new CultureInfo(1033), Kind.Fruit, button2, "banana"), 24 new Datum(new CultureInfo(1033), Kind.Fruit, button3, "grape"), 25 }; 26 27 var text = data 28 .Where(a => a.Culture.LCID == 1041 && a.Kind == Kind.Fruit && a.Button == button1) 29 .FirstOrDefault()?.Text; 30 Console.WriteLine(text ?? "みつかりませんでした"); 31 } 32 } 33 34 public enum Kind 35 { 36 Fruit, Animal, Vehicle 37 } 38 39 public class Datum 40 { 41 public Datum(CultureInfo culture, Kind kind, Button button, string text) 42 { 43 Culture = culture; 44 Kind = kind; 45 Button = button; 46 Text = text; 47 } 48 public CultureInfo Culture { get; set; } 49 public Kind Kind { get; set; } 50 public Button Button { get; set; } 51 public string Text { get; set; } 52 } 53}

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

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

投稿2018/05/14 02:34

Zuishin

総合スコア28660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2018/05/14 02:36

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

2018/05/14 04:35

ありがとうございます。 btnという記述が誤解を生んでいる気がしましたのでコードを書き直しました。 実際の処理としては最初の画面でユーザーが言語選択をボタンで選択し、このとき日本語(ja)が選ばれれば次のページ(fruit選択ページ)で日本語テキストのボタンを表示させます。 このとき、多次元連想配列を用意しておけば言語と選択項目を表すfruitを指定すればあとはループでバインドさせてボタンのテキストを書き換えできるはずです。 そして最後のページでは、選択した内容を「日本語」+「選択した言語」で表示させる必要があるため、選択した内容をkey(この場合はappleやbanana)で持っておけば、あとからどの言語を呼び出す場合でも多次元連想配列から容易に取得できると考えました。 この構造はおかしいでしょうか。 多言語化の方法が別にあることは理解しましたが、そこはまた別の話として多次元連想配列からデータを取得するという構造に問題があるのであれば、どのように実装するのが一般的なのかが知りたいかったのですが、Dictionaryで多次元連想配列を生成することが特に問題なければその方法で実装しようと思います。
Zuishin

2018/05/14 05:02

ローカルアプリであろうと Web アプリであろうと、アプリケーションのインストール時点もしくは開始時点で言語を選択させ、以降は設定が変更されるまでそれを使うのが通常です。 画面毎に言語を選択させたり、多言語のリソースをすべてオンメモリに持つようなことはあまりしません。 また選択肢が果物しかないなら fruit キーは必要ありません。 動けば勝ちという考え方もありますので、オブジェクト指向に慣れていないならとりあえずそれでやってみればいいのではないかと思います。 多階層 Dictionary を使ってはいけないというのは、使ったらまずいのではなく、ちゃんと設計すれば使うような状況があまりないということにすぎませんから。
Anon_

2018/05/14 05:49

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

0

ベストアンサー

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

【追伸】

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 01:23

編集2018/05/14 06:28
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Anon_

2018/05/14 01:39

移行という書き方が悪かったですね。単にPHPを最初に学び、新たにC#を学習しているという意味です。 WebアプリではなくスマホアプリをC#で作成しようとしています。 リソースについては確かにそうかもしれません。 ではC#でどのように実現するのがよくわかりません。
退会済みユーザー

退会済みユーザー

2018/05/14 02:23 編集

> ではC#でどのように実現するのがよくわかりません。 質問に書いてある例では自分は多言語化の話しか想像できないので、多言語化以外のことで「どのように実現」という話をするのは難しいです。 多言語化の他に PHP での連想配列の作り方・使い方の具体例を出してもらって、それを C# で実装するにどうするかという話をしていただければ、何か案が出てくるかもしれません(出てこなかったらスミマセンが)。
Anon_

2018/05/14 02: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 03:46

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

2018/05/14 04:44

なるほど。そういう書き方ができるのですね! 私が知りたかった答えをいただけた気がします。 一度この方法で書いてみたいと思います。
退会済みユーザー

退会済みユーザー

2018/05/14 05:03

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

2018/05/14 05:52

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

退会済みユーザー

2018/05/14 06:21

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

2018/05/14 06:23

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

2018/05/14 06:37

追記拝見しました。そのような書き方もできてしまうのですね。 私も一目みて気に入ったのでLINQを使ったやり方で実装できるかやってみたいとおもいます。 また、ここまでで私が求めていた回答をくださったSurferOnWww様をベストアンサーとさせていただきたいと思います。 いろいろと勉強になりました。ありがとうございます。 実装ができたあとで解決方法を記載したいと思います。
Anon_

2018/05/14 09:36

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

0

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

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

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

ポエムでした。

投稿2018/05/14 02:49

kazto

総合スコア7196

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

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

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

投稿2018/05/14 01:17

tacsheaven

総合スコア13703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Anon_

2018/05/14 01:44

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

2018/05/14 01:54

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

0

こんにちは。

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

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

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

投稿2018/05/14 01:40

編集2018/05/14 01:41
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Anon_

2018/05/14 01:49

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

2018/05/14 02:21

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

2018/05/14 02:30

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

0

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

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

投稿2018/05/14 01:21

編集2018/05/14 02:07
hihijiji

総合スコア4150

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Anon_

2018/05/14 02:37

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

2018/05/14 02:52

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問