Quantcast
Browsing Latest Articles All 31 Live
Mark channel Not-Safe-For-Work? (0 votes)
Are you the publisher? or about this channel.
No ratings yet.
Articles:

PHPの連想配列について(Progate)

学習コース

Progate
PHP 道場コース Ⅰ → 連想配列の操作をマスターしよう9. → 全ての価格を表示しよう

ソースコード

<?php
$menus = array(
  array('name' => 'CURRY', 'price' => 900),
  array('name' => 'PASTA', 'price' => 1200),
  array('name' => 'COFFEE', 'price' => 600)
);

// この下にコードを書いてください
foreach ($menus as $menu) {
  echo $menu['name']."は".$menu['price']."円です";
  echo '<br>';
}

?>

---出力結果---
CURRYは900円です
PASTAは1200円です
COFFEEは600円です

質問内容

  foreach ($menus as $menu) { ~~~~}

↑foreach内にあるこの[$menu]はどこからきたのでしょうか?
[$menus]は最初に定義されているのでわかるのですが。
例えばここが[$prices]なら[$price]といったように
単純に複数形「s」を取ったものになるのでしょうか?

【C#】WPFアプリケーションで連想配列を使う

配列

配列を宣言すると、要素が割り当てられます。C#で配列を宣言すると以下のようになります。

int[] array = new int[4]

array配列には[0]~[3]まで利用可能な配列要素が生成されます。
例えば、身長の集合$A = \{160, 170, 180\}$があったとし、これを配列に対応させれば次のようになります。

array[0] = 160;
array[1] = 170;
array[2] = 180;

配列は同じデータ集合でそれぞれの値を保持するのによく用います。

連想配列

同じデータの集合であればいいのですが、配列要素ごとに別のデータの集合を入れておくとき、名前がついていないと不便です。そこで、配列要素1つ1つに名前を付けて管理すれば、配列の何番目がどのデータを示しているかが分かりやすくなります。連想配列は Dictionary インスタンスを用いて宣言します。

//Dictionary インスタンスを使うための Using ディレクティブ
using System.Collections.Generic; 
//Dictionary の宣言
var array = new Dictionary<"Keyの型", "Valueの型">();

< > の中には <キーの型, 値の型> を指定することで各配列要素をキーとして管理し、その管理しているキーに値を入れておくことができます。キーと値を追加するには Add メソッドを用います。

array.Add("配列の名前(Key)", "配列に代入する値(Value)");

例えば、速度の集合$ V = \{10, 20, 30\}$ 、質量の集合$ M = \{2, 3, 4\}$ 、大きさの集合$ S = \{100, 120, 150\}$があったとし、各集合から1つのデータを無作為に抽出したとすればイメージとして次のようになります。(あくまでイメージです。)

array[速度V] = 20 -----> 速度 (array[0]) には 20 という値が結びつく
array[質量M] = 2 ------> 質量 (array[1]) には 170 という値が結びつく
array[大きさS] = 100 --> 大きさ (array[2]) には 100 という値が結びつく

このようにすれば「配列の何番がどのデータを示すんだっけ...?」という心配がなくなります。

Dictionary のメソッドの .Keys と .Values について

Dictionary には様々なメソッドがあります。Key だけ、Value だけを取り出す方法があり、どちらかを取得して利用することもできる。先ほどの Dictionary と Add であらかじめ連想配列が定義されているとしたときを考えます。(Key, Value 共に string 型として扱います。)

Dictionary で宣言した連想配列の Key だけを取り出す場合

//キーを保管するための配列
string[] key = new string[4];
int i = 0;

//キーが存在する回数だけ繰り返し、key に保管する
foreach(string Key in array.Keys)
{
       key[i] = Key;
       i++;
}

Dictionary で宣言した連想配列の Value だけを取り出す場合

//値を保管するための配列
string[] value = new string[4];
int j = 0;

//値が存在する回数だけ繰り返し、value に保管する
foreach(string Value in array.Values)
{
       value[j] = Value;
       j++;
}

WPFでの実装

ここまでの内容を使って、実際に実装してみます。まずはUIから。
適当にオブジェクトを配置していきます。
2019-05-27 (2).png
XAMLコードも載せておきます。

MainWindow.xaml
<Window x:Class="_006_連想配列.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:_006_連想配列"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="300">
    <Grid>
        <Label Content="配列[0]" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
        <Label Content="配列[1]" HorizontalAlignment="Left" Margin="10,41,0,0" VerticalAlignment="Top"/>
        <Label Content="配列[2]" HorizontalAlignment="Left" Margin="10,72,0,0" VerticalAlignment="Top"/>
        <Label Content="配列[3]" HorizontalAlignment="Left" Margin="10,103,0,0" VerticalAlignment="Top"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="58,14,0,0" TextWrapping="Wrap" Text="なにか" VerticalAlignment="Top" Width="120" x:Name="Textbox0"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="58,44,0,0" TextWrapping="Wrap" Text="文字を" VerticalAlignment="Top" Width="120" x:Name="Textbox1"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="58,75,0,0" TextWrapping="Wrap" Text="入力" VerticalAlignment="Top" Width="120" x:Name="Textbox2"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="58,107,0,0" TextWrapping="Wrap" Text="してみて" VerticalAlignment="Top" Width="120" x:Name="Textbox3"/>
        <Button Content="書き換える" HorizontalAlignment="Left" Margin="58,139,0,0" VerticalAlignment="Top" Width="90" Click="Button_Write" />
        <Label Content="配列名" HorizontalAlignment="Left" Margin="197,10,0,0" VerticalAlignment="Top" x:Name="Label_array0" Height="27"/>
        <Label Content="配列名" HorizontalAlignment="Left" Margin="197,41,0,0" VerticalAlignment="Top" Height="26" x:Name="Label_array1"/>
        <Label Content="配列名" HorizontalAlignment="Left" Margin="197,72,0,0" VerticalAlignment="Top" Height="27" x:Name="Label_array2"/>
        <Label Content="配列名" HorizontalAlignment="Left" Margin="197,107,0,0" VerticalAlignment="Top" Height="27" x:Name="Label_array3"/>
        <Button Content="表示" HorizontalAlignment="Left" Margin="161,139,0,0" VerticalAlignment="Top" Width="90" Click="Button_Show"/>
    </Grid>
</Window>

続いてロジックを実装します。

MainWindow.xaml.cs
using System.Windows;
using System.Collections.Generic;

namespace _006_連想配列
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        //連想配列にテキストボックスの情報を書き込む
        static void Array_Write()
        {
            //Textbox は MainWindow に存在するのでインスタンス化する必要がある。
            //インスタンスを取得した上でその中の TextBox を使う
            var mainWindow = (MainWindow)App.Current.MainWindow;

            //連想配列は Dictionary<> を用いる
            //<配列の名前, 配列に入れるデータ>の各型を宣言する
            var array = new Dictionary<string, string>();

            //キーを個別に保管しておくための配列(変換する)
            string[] key = new string[4];

            //値を個別に保管しておくための配列(変換する)
            string[] value = new string[4];

            //foreach を回すための初期値
            int i = 0;

            //各要素に配列名とそこに入れるデータを参照する
            array.Add("配列1", mainWindow.Textbox0.ToString());
            array.Add("配列2", mainWindow.Textbox1.ToString());
            array.Add("配列3", mainWindow.Textbox2.ToString());
            array.Add("配列4", mainWindow.Textbox3.ToString());

            //array のキーの数だけ繰り返して、キーを個々に格納
            foreach(string Key in array.Keys)
            {
                key[i] = Key;
                i++;
            }

            //ウィンドウの配列名のところに設定した配列名が更新される
            mainWindow.Label_array0.Content = key[0];
            mainWindow.Label_array1.Content = key[1];
            mainWindow.Label_array2.Content = key[2];
            mainWindow.Label_array3.Content = key[3];
        }

        private void Button_Write(object sender, RoutedEventArgs e)
        {
            //連想配列へ書き込む
            Array_Write();
            MessageBox.Show("書き込みました");
        }

        private void Button_Show(object sender, RoutedEventArgs e)
        { 
            MessageBox.Show("配列名 " + Label_array0.Content + " には " + Textbox0.Text + " が代入されています。");
            MessageBox.Show("配列名 " + Label_array1.Content + " には " + Textbox1.Text + " が代入されています。");
            MessageBox.Show("配列名 " + Label_array2.Content + " には " + Textbox2.Text + " が代入されています。");
            MessageBox.Show("配列名 " + Label_array3.Content + " には " + Textbox3.Text + " が代入されています。");
        }
    }
}

このアプリは MainWindow画面の Textbox で受け取ったデータを Dictionaly で宣言した連想配列に書き込みます。
連想配列名は"配列1"になっていますが、ここを書きかえればKeyの値(各配列の名前)が変わります。このプログラムでは array[0] を配列1、array[1] を配列2 ...というように各配列に名前を付けています。
受け取ったデータを、Button_show にて Key と関連付けて Value が表示されます。

ぜひ実行してみてください。

プログラムの実行

まずはテキストボックスに好きな文字を入力します。
2019-05-28 (2).png

"書きかえる" をクリックすると、Button_Write イベントが実行され、Array_Write 関数によって連想配列に Value が書き込まれます。
2019-05-28 (1).png
書き込まれるとメッセージボックスが表示され、配列名の部分の表示がロジックで設定した Key が代入されます。
2019-05-28 (2)_LI.jpg

"表示" をクリックするとメッセージボックスにて、各配列の Key と Value の値がどのように関連付けられているかを確認することができます。
2019-05-28 (3).png

ここまでが一連の動作です。あとはロジック側で Key をいじってみると配列名が変わるのでいろいろ試してみると面白いと思います。
作ったものはこちらです。

最後に

たまたま配列の各要素に名前を付けたいと思っていたら Dictionary インスタンスについての記事が見つかりました。
参考 : https://www.sejuku.net/blog/41326
これをコンソールアプリではなく、Windowsアプリとして扱いたいと思って作ってみました。もし、使う機会があるとするならば、オブジェクト1つに対して様々なデータを含ませるときに使うかなと思います。(だったらクラスでもいい気が...)

皆様の参考になれば幸いです。

[JS]オブジェクトや配列をコピーすると、コピー元の編集がコピー先にも反映される件

今日のコード

問題1 ふつうの値の場合

問題1
let a = 1;
let b = a;
a = 100; // 後からaにだけ100を代入し直す。
console.log(b); // さてbには何が入っているでしょう。 1? 100?

さて、これで出力される値は、どちらでしょうか?
正解は…

答え1
1

正解は、1ですね。これはまぁ、当然かと思います。
bにaが代入された時点で、b=1という、値が代入されているので、その後aに違う値が代入されても、bはそのまま1です。

問題2 オブジェクトの場合

問題2
let obj1 = {'one':''};
let obj2 = obj1;
obj1.one = ''; // 後からobj1にだけ「い」を代入し直す。
console.log(obj2); // さてこれは? 「あ」? 「い」?

これはどうか。

答え2
{one: "い"}

こちらでは、なんと再代入していない方(再代入前にコピーされたもう一方)も、値が「い」になってしまいました。

問題3 配列の場合

問題3
let arr1 = [1,2,3];
let arr2 = arr1;
arr1[0] = 10000; // 後からarr1にだけ10000を代入し直す。
console.log(arr2[0]); // さてこれは? 1? 100?

こちらはどうか。

答え3
10000

はい。オブジェクトの場合と同様に、再代入していない方(再代入前にコピーされたもう一方)にも、影響がありました。
以下で詳しく説明します。

どういうことか

これは、JavaScriptのコピー(値を渡す挙動)における仕様によるものです。

JavaScriptでは、配列やオブジェクトがコピーされた場合(値が渡された場合)、基本的に参照渡しで渡される。

つまり、新しいarr2やobj2が作られて、新たに値が入れられるわけではない。
実は内部的には、arr2はarr1と同じものを常に参照しているだけ、(obj2はobj1を常に参照しているだけ)という状態になっている。

これにより、コピー元を変更すると、コピー先も影響を受けてしまうので、注意が必要です。
コピーしたい場合は、使い勝手が良いと噂のlodashの「_.deepClone関数」などを使うようにしましょう。

[JS]連想配列に任意の値と等しい要素があれば、それらのインデックスを全て取ってくるサンプル~map編~

2019/07/21追記

コメント欄に、とても的確なご指摘を頂いております。
内容としては、

  • 今回はmapではなくforEachで書くべき
  • 偽を捨てるなら三項演算子じゃなくif文ワンライナーで良いのでは

とのことでした。
まさに、おっしゃられる通りですので、ぜひ皆様にもコメント欄を見てもらえればと思います。
また、その過程で本記事は、あえてそのまま残しておこうと思います。

いきなり結論コード

See the Pen 配列の一致インデックス取得map版 by riotam (@riotam4) on CodePen.

解説

キモになる部分
      let idx = []
      this.users.map((v,k) => v.gender == '' ? idx.push(k) : []) // ここはコメント欄で指摘を頂いております。そちらもご参照ください。
      return idx

まず、idxという変数を用意。
this.usersにデータが入っているので、それらをmapします。

mapメソッドの引数は、関数型で書く必要があり、アロー関数と三項演算子でワンライナーにしてしまってます。
要は、this.usersをv(value)とk(key)にして順番に呼び出す。
→そのvのgenderキーが'男'と等しければ、idx変数にpushしていく。そうじゃなければ、という感じ。

ちなみに

[]部分はnull''0など、falsyなものなら、挙動に問題はありません。

2019/07/21追記 : ここはコメント欄で指摘を頂いております。そちらもご参照ください。

最後に

さいごまでありがとうございました。

関連記事

同じ挙動のものをflatMapで作ってみました。こちら

連想配列の特定のキーの値が同じものを一つに絞る

自分で調べていてあまり適切なものがネットで見つからなかったので、ここに残しておきます。
言語はPythonで書いておりますが、他の言語でも応用できるので、コメントを中心に読んでいってください。

# ピカチュウが被っているので
data = [
    {"species": "ピカチュウ", "color": "yellow" , "animal": "ねずみ"},
    {"species": "カイリュー", "color": "orange" , "animal": "ドラゴン"},
    {"species": "ヤドラン", "color": "pink" , "animal": "やどかり"},
    {"species": "ピカチュウ", "color": "orange" , "animal": "ねずみ"},
    {"species": "ビジョン", "color": "purple" , "animal": "とり"},
    {"species": "コダック", "color": "yellow" , "animal": "あひる"},
    {"species": "ピカチュウ", "color": "white" , "animal": "ねずみ"}
]

# こうして、ピカチュウを一つにしたい
new_data = [
    {"species": "ピカチュウ", "color": "yellow" , "animal": "ねずみ"},
    {"species": "カイリュー", "color": "orange" , "animal": "ドラゴン"},
    {"species": "ヤドラン", "color": "pink" , "animal": "やどかり"},
    {"species": "ビジョン", "color": "purple" , "animal": "とり"},
    {"species": "コダック", "color": "yellow" , "animal": "あひる"}
]

コード

data = [
    {"species": "ピカチュウ", "color": "yellow" , "animal": "ねずみ"},
    {"species": "カイリュー", "color": "orange" , "animal": "ドラゴン"},
    {"species": "ヤドラン", "color": "pink" , "animal": "やどかり"},
    {"species": "ピカチュウ", "color": "orange" , "animal": "ねずみ"},
    {"species": "ビジョン", "color": "purple" , "animal": "とり"},
    {"species": "コダック", "color": "yellow" , "animal": "あひる"},
    {"species": "ピカチュウ", "color": "white" , "animal": "ねずみ"}
]

# 重複を削りたいkeyの値を追加していく配列
species_array = []
# 新たにできる連想配列
new_data = []

# データ1つ1つに処理を行う
for pokemon in data:
    # 重複を削りたいkeyの値を変数に入れる
    species = pokemon["species"]
    # 重複を削りたいkeyの値を追加した配列に同じ値がなければ
    if(species not in species_array):
        # 重複を削りたいkeyの値を追加した配列に新たな値を追加して
        species_array.append(species)
        # 新たにできる連想配列にデータを追加する
        new_data.append(pokemon)

「他にもこんなやり方あるよ」とか、
「こういうコードの応用方程式集みたいなものあるよ」とか、
コメント残していってもらえると助かります。

連想配列の基本操作【JavaScript/C#/VB/Python/CommonLisp/HSP】

最近いくつかの言語の連想配列の操作を調査したのでそれをここにまとめておく。

JavaScript

JavaScriptで連想配列を使うには昔ながらのオブジェクトを使ったものとES6で追加されたMapクラスを使う方法があります。

Object

"use strict";

//初期化
const kantoh={
    "茨城県":"水戸市",
    "栃木県":"宇都宮市",
    "群馬県":"前橋市",
    "埼玉県":"さいたま市",
    "神奈川県":"横浜市"
};
//代入
kantoh["千葉県"]="千葉市";
//要素の有無
console.log("千葉県" in kantoh);
//追加と代入は同じ
kantoh["東京都"]="新宿区";
//要素が登録済みなら代入したくない場合
if(!("東京都" in kantoh)){
    kantoh["東京都"]="新宿区";
}
else{
    console.log("同一のキーを含む項目が既に追加されています。");
}
//取得
console.log(kantoh["千葉県"]);
//代入演算子も使用可
kantoh["千葉県"]+="中央区";
console.log(kantoh["千葉県"]);
//要素数
console.log(Object.keys(kantoh).length);
//要素の削除
delete kantoh["千葉県"];
//キーの配列
console.log(Object.keys(kantoh).join(","));
//値の配列
console.log(Object.values(kantoh).join(","));
//ループ
for(let [key,value] of Object.entries(kantoh)){
    console.log(`key:${key} value:${value}`);   
}
//Join
const joinDict=
    dict=>Object.entries(dict).map(v=>v.join(":")).join(", ");
console.log(joinDict(kantoh));
//要素のクリア
for(let i of Object.keys(kantoh)) delete kantoh[i];
kantoh["なし"]="なにもないよ";
console.log(joinDict(kantoh));

Map

"use strict";

//初期化
const kantoh=new Map([
    ["茨城県","水戸市"],
    ["栃木県","宇都宮市"],
    ["群馬県","前橋市"],
    ["埼玉県","さいたま市"],
    ["神奈川県","横浜市"]
]);
//代入
kantoh.set("千葉県","千葉市");
//要素の有無
console.log(kantoh.has("千葉県"));
//追加と代入は同じ
kantoh.set("東京都","新宿区");
//要素が登録済みなら代入したくない場合
if(!kantoh.has("東京都")){
    kantoh.set("東京都","新宿区");
}
else{
    console.log("同一のキーを含む項目が既に追加されています。");
}
//取得
console.log(kantoh.get("千葉県"));
//代入演算子は使用不可
const resetAdd=(dict,key,value)=>dict.set(key,dict.get(key)+value);
resetAdd(kantoh,"千葉県","中央区");
console.log(kantoh.get("千葉県"));
//要素数
console.log(kantoh.size);
//要素の削除
kantoh.delete("千葉県");
//キーの配列
console.log(Array.from(kantoh.keys()));
//値の配列
console.log(Array.from(kantoh.values()));
//ループ
for(let [key,value] of kantoh){
    console.log(`key:${key} value:${value}`);   
}
//Join
const joinDict=
    dict=>Array.from(dict).map(v=>v.join(":")).join(", ");
console.log(joinDict(kantoh));
//要素のクリア
kantoh.clear();
kantoh.set("なし","なにもないよ");
console.log(joinDict(kantoh));

Mapは最近新しく追加された機能であるだけあってメソッドが綺麗に整備されています。
しかし、初期化や取得、代入リテラルがオブジェクトに比べて少し不自然なのが辛いところ。

Python

#初期化
kantoh={
    "茨城県":"水戸市",
    "栃木県":"宇都宮市",
    "群馬県":"前橋市",
    "埼玉県":"さいたま市",
    "神奈川県":"横浜市"
}
#代入
kantoh["千葉県"]="千葉市"
#要素の有無
print("千葉県" in kantoh)
#追加と代入は同じ
kantoh["東京都"]="新宿区"
#要素が登録済みなら代入したくない場合
if "東京都" not in kantoh:
    kantoh["東京都"]="新宿区"
else:
    print("同一のキーを含む項目が既に追加されています。")
#取得
print(kantoh["千葉県"])
#代入演算子も使用可
kantoh["千葉県"]+="中央区"
print(kantoh["千葉県"])
#要素数
print(len(kantoh))
#要素の削除
del kantoh["千葉県"]
#キーの配列
print(list(kantoh.keys()))
#値の配列
print(list(kantoh.values()))
#ループ
for key,value in kantoh.items():
    print(f"key:{key} value:{value}")
#Join
joinDict=(
    lambda dict:",".join([":".join(v) for v in dict.items()]))
print(joinDict(kantoh))
#要素のクリア
kantoh.clear()
kantoh["なし"]="なにもないよ"
print(joinDict(kantoh))

Pythonのdictは言語レベルで組み込まれていてリテラルも何も不自由なく使用できます。

C#

using System;
using System.Collections.Generic;
using System.Linq;

class Program{
    static void Main(){
        //初期化
        var kantoh=new Dictionary<string,string>{
            {"茨城県","水戸市"},
            {"栃木県","宇都宮市"},
            {"群馬県","前橋市"},
            {"埼玉県","さいたま市"},
            {"神奈川県","横浜市"}
        };
        //代入
        kantoh["千葉県"]="千葉市";
        //要素の有無
        Console.WriteLine(kantoh.ContainsKey("千葉県"));
        //追加
        kantoh.Add("東京都","新宿区");
        //要素が登録済みの場合、ArgumentException
        try{
            kantoh.Add("東京都","新宿区");
        }
        catch(ArgumentException ex){
            Console.WriteLine(ex.Message);
        }
        //取得
        Console.WriteLine(kantoh["千葉県"]);
        //代入演算子も使用可
        kantoh["千葉県"]+="中央区";
        Console.WriteLine(kantoh["千葉県"]);
        //要素数
        Console.WriteLine(kantoh.Count);
        //要素の削除
        kantoh.Remove("千葉県");
        //キーの配列
        Console.WriteLine(string.Join(",",kantoh.Keys));
        //値の配列
        Console.WriteLine(string.Join(",",kantoh.Keys));
        //ループ
        foreach(var v in kantoh){
            Console.WriteLine($"key:{v.Key} value:{v.Value}");
        }
        //Join
        Func<Dictionary<string,string>,string> joinDict=
            dict=>string.Join(", ",dict.Select(v=>v.Key+":"+v.Value));
        Console.WriteLine(joinDict(kantoh));  
        //要素のクリア
        kantoh.Clear();
        kantoh["なし"]="なにもないよ";
        Console.WriteLine(joinDict(kantoh));  
    }
}

極々普通な辞書。静的言語なので型定義はしておく必要があります。

VB

Option Strict On
Option Infer On
Imports System.Collections.Generic
Imports System.Linq

Module Program
    Sub Main()
        '初期化
        Dim kantoh As New Dictionary(Of String,String) From {
            {"茨城県","水戸市"},
            {"栃木県","宇都宮市"},
            {"群馬県","前橋市"},
            {"埼玉県","さいたま市"},
            {"神奈川県","横浜市"}
        }
        '代入
        kantoh("千葉県")="千葉市"
        '要素の有無
        Console.WriteLine(kantoh.ContainsKey("千葉県"))
        '追加
        kantoh.Add("東京都","新宿区")
        '要素が登録済みの場合、ArgumentException
        Try
            kantoh.Add("東京都","新宿区")
        Catch ex As ArgumentException
            Console.WriteLine(ex.Message)
        End Try
        '取得
        Console.WriteLine(kantoh("千葉県"))
        '代入演算子も使用可
        kantoh("千葉県")+="中央区"
        Console.WriteLine(kantoh("千葉県"))
        '要素数
        Console.WriteLine(kantoh.Count)
        '要素の削除
        kantoh.Remove("千葉県")
        'キーの配列
        Console.WriteLine(String.Join(",",kantoh.Keys))
        '値の配列
        Console.WriteLine(String.Join(",",kantoh.Keys))
        'ループ
        For Each v In kantoh
            Console.WriteLine($"key:{v.Key} value:{v.Value}")
        Next
        'Join
        Dim joinDict As Func(Of Dictionary(Of String,String),String)=
            Function(dict) String.Join(", ",dict.Select(Function(v) v.Key & ":" & v.Value))
        Console.WriteLine(joinDict(kantoh))
        '要素のクリア
        kantoh.Clear()
        kantoh("なし")="なにもないよ"
        Console.WriteLine(joinDict(kantoh))
    End Sub
End Module

C#と同じ。

HSP

HSPの言語機能に連想配列なんてものは存在しないので
以前自作した連想配列モジュール「DictionaryOnHSP」を使用します。
大体.NET(C#,VB)っぽい命令/関数群が用意されています。

#runtime "hsp3cl"
#cmpopt varinit 1
#include "Dictionary.as"

;初期化
new@Dictionary kantoh,"str",,,{"
    茨城県:水戸市,
    栃木県:宇都宮市,
    群馬県:前橋市,
    埼玉県:さいたま市,
    神奈川県:横浜市
"}
;代入
dcSet kantoh,"千葉県","千葉市"
;要素の有無
mes dcContainsKey(kantoh,"千葉県")
;追加
dcAdd kantoh,"東京都","新宿区"
;要素が登録済みの場合、stat1が返り何もしない
dcAdd kantoh,"東京都","新宿区"
if 1=stat{
    mes "同一のキーを含む項目が既に追加されています。"
}
;取得
mes dcItem(kantoh,"千葉県")
;代入演算子っぽい何かも使用可
dcReSet kantoh,"千葉県","+","中央区"
mes dcItem(kantoh,"千葉県")
;要素数
mes dcCount(kantoh)
;要素の削除
dcRemove kantoh,"千葉県"
;キーの配列
sdim keys: dcRefKeys kantoh,keys
mes dcJoinArray(keys,",")
;値の配列
sdim values: dcRefValues kantoh,values
mes dcJoinArray(values,",")
;ループ
dcForeach kantoh
    mes strf("key:%s value:%s",dcKeys(kantoh,cnt),dcValues(kantoh,cnt))   
loop
;Join
mes dcJoinDict(kantoh,":",",")   
;要素のクリア
dcClear kantoh
dcSet kantoh,"なし","なにもないよ"
mes dcJoinDict(kantoh)

CommonLisp

全体的にかなり冗長。
連想リストという選択肢もあります。

(let(
        ;初期化
        (kantoh (make-hash-table :test #'equal)))
    ;初期化は愚直
    (setf
        (gethash "茨城県" kantoh) "水戸市"
        (gethash "栃木県" kantoh) "宇都宮市"
        (gethash "群馬県" kantoh) "前橋市"
        (gethash "埼玉県" kantoh) "さいたま市"
        (gethash "神奈川県" kantoh) "横浜市")
    (format t "~A~%" (gethash "千葉県" kantoh))
    ;代入
    (setf (gethash "千葉県" kantoh) "千葉市")
    ;要素の有無 gethashの返り値の2価を
    (format t "~A~%" (multiple-value-list(gethash "千葉県" kantoh)))
    ;追加と代入は同じ
    (setf (gethash "東京都" kantoh) "新宿区")
    ;要素が登録済みなら代入したくない場合
    (if (not(cadr(multiple-value-list(gethash "東京都" kantoh))))
        (setf (gethash "東京都" kantoh) "新宿区")
        (write-line "同一のキーを含む項目が既に追加されています。"))
    ;取得
    (format t "~A~%" (gethash "東京都" kantoh))
    ;代入演算子なんてない
    (setf (gethash "千葉県" kantoh)
        (concatenate 'string (gethash "千葉県" kantoh) "中央区"))
    ;要素数
    (format t "~d~%" (hash-table-count kantoh))
    ;要素の削除
    (remhash "千葉県" kantoh)
    ;キーの配列
    (format t "~A~%" (loop for key being the hash-keys in kantoh collect key))
    ;値の配列
    (format t "~A~%" (loop for key being the hash-keys in kantoh using (hash-value value) collect value))
    ;ループ
    (maphash #'(lambda(key value)
            (format t "key:~A value:~A~%" key value))
        kantoh)
    ;Join
    (labels((joinDict(dict)
            (format nil "~{~A~^,~}" 
                (mapcar #'(lambda(item) (concatenate 'string (car item) ":"  (cadr item)))
                    (loop for key being the hash-keys in kantoh using (hash-value value) collect
                        (list key value))))))
        (format t "~A~%" (joinDict kantoh))
        ;要素のクリア
        (maphash #'(lambda(key value) (remhash key kantoh)) kantoh)
            (setf (gethash "なし" kantoh) "なにもないよ")
            (format t "~A~%" (joinDict kantoh))))

PHP 連想配列をObject(stdClassのインスタンス)へ変換

$testarr = ['t1' => 'sss1','t2' => 'sss2'];
dump($testarr);
dump((object)$testarr);

echo $testarr['t1'];
echo ((object)$testarr)->t1;

stdClass.PNG

C++のmap, unordered_mapの使い方: 連想配列が扱える

C++ での連想配列の使い方

C++ で連想配列を使うために mapコンテナを使います
使い方は簡単で下記ように宣言するだけで, 連想配列が扱えるようになります

map<string, int> mp;

では下記の2個のプログラムを参考に説明していきます

通常の連想配列同様 mp[key] に値の入力を行い, 出力することができます.
また, mp["fish"] のように初期化されていないものは 0 が出力されます.

exsample.cpp
#include<bits/stdc++.h>
using namespace std;

int main(){
    map<string, int> mp;
    mp["dog"] = 3;
    mp["cat"] = 1;
    mp["python"] = 4;

    cout << mp["dog"] << endl; //3
    cout << mp["cat"] << endl; // 1
    cout << mp["python"] << endl; // 4
    cout << mp["fish"] << endl; //0
}

ループ使用方法及び, キー, 値の取得方法は下記のようにできます.

exsample2.cpp
#include<bits/stdc++.h>
using namespace std;

int main(){
    map<string, int> mp;
    mp["dog"] = 3;
    mp["cat"] = 1;
    mp["python"] = 4;

    for(auto itr=mp.begin(); itr!=mp.end(); itr++) {
        cout << "key = " << itr->first;      // キーを表示      
        cout << ", val = " << itr->second << endl;    // 値を表示
    }
}

exsample2.cpp の実行結果が下記のoutput.txtです.

output.txt
key = cat, val = 1
key = dog, val = 3
key = python, val = 4

おまけ

競技プログラマーの人は下記の問題で連想配列を使ってみてね!
ABC008-b 投票

unordered_map が高速だと聞いたので速度比較してみた

"map.cpp" と "unordered_map.cpp"の実行時間を time で測ってみた!

g++ -O0 map.cpp
time ./a.out 
g++ -O0 unordered_map.cpp
time ./a.out 
map.cpp
#include<bits/stdc++.h>
using namespace std;

int main(){
    map<string, int> mp;

    for(int i=0; i<1e7; i++){
        string s = to_string(i);
        mp[s]= i;
    }

    for(auto itr=mp.begin(); itr!=mp.end(); itr++) {
        string a = itr->first;      // キーを表示
        int b = itr->second;
    }
}

unordered_map.cpp
#include<bits/stdc++.h>
using namespace std;

int main(){
    unordered_map<string, int> mp2;
    for(int i=0; i<1e7; i++){
        string s = to_string(i);
        mp2[s]= i;
    }

    for(auto itr=mp2.begin(); itr!=mp2.end(); itr++) {
        string a = itr->first;
        int b = itr->second;
    }
}

実行結果

実行結果は下記のようになった.
map.cpp: 19.24s
unordered_map.cpp: 15.49s

大きな差ではないが, 有意な差は見られた

phpを使ったjsonファイルの出力

はじめに

jsonをphpで読み込んで表示する機会があったのでここに書き留めておきます。

概要

  1. jsonファイルを用意
  2. phpで読み込み
  3. 出力

手順

jsonファイル作成

まず、出力するjsonファイルを用意します。

今回はdata.jsonを作成します。

[
    {
        "name": "Aさん",
        "department": "営業",
        "text": [
            "今月の売り上げは先月の2倍の見込みです",
            "先月の遅れを取り戻します"
        ]
    },
    {
        "name": "B",
        "department": "人事",
        "text": [
            "就活生とお話する機会があって楽しいです"
        ]
    },
    {
        "name": "C",
        "department": "経理",
        "text": [
            "1桁のミスも許されない世界です"
        ]
    }
]

phpで読み込み

<?php
$file = "./data.json";
$json = file_get_contents($file);
$data = json_decode($json, true);
?>
  • $file:jsonファイルへのパス
  • $jsonfile_get_contents関数を用いて、$fileの内容を文字列として読み込む
  • $data$jsonの内容を連想配列として$dataに格納する

$dataにどのような感じでjsonデータが格納されているか挙げると、

$data[0]["name"] => "A"
$data[0]["department"] => "営業"
$data[0]["text"][0] => "今月の売り上げは先月の2倍の見込みです"
$data[0]["text"][1] => "先月の遅れを取り戻します"
$data[1]["name"] => "B"
$data[1]["department"] => "人事"
・・・

このように、phpの連想配列として$dataに格納されています。

echo var_dump($data)

と打つと、連想配列の様子が確認できます。

出力

最後に、htmlとして出力をします。

ここまでくれば、あとは連想配列の出力と同じです。

<?php
for($i=0; $i<count($data); $i++){
    print<<<EOT
    <div style="margin: 10px; padding: 5px; border: solid 1px #000000;">
        <p>名前:{$data[$i]["name"]}</p>
        <p>所属:{$data[$i]["department"]}</p>
        <p>
EOT;
        for($k=0; $k<count($data[$i]["text"]); $k++){
            print<<<EOT
            {$data[$i]["text"][$k]}<br>
EOT;
        }
        print<<<EOT
        </p>
    </div>

EOT;
}
?>

textのところ(2回目のfor文)で、そこが配列になっているのでやや複雑になっています。

結果をブラウザで見ると、

json.png

と、出力されているのが確かめられました!

最後に

今回の場合はjsonファイルのデータ容量がそれほど多くなく、言ってしまえばphpに連想配列を直書きできる内容でした。

もしそのような場合はjsonを使う必要はないと思います。

ただ、データ数や項目数が多い場合は、データを格納する専用のファイルとしてjsonを使うのをお勧めします。

(データベースの知識があれば、MySQL等を使ったほうが良いと聞くのですが、私はまだそのスキルが十分ではないのでjsonを使っています)

【JavaScript】オブジェクト(連想配列)を結合する

Object.assign()を使用した方法

const obj1    = { a: 1, b: 2, c: 3 };
const obj2    = { d: 4, e: 5, f: 6 };
const result1 = Object.assign(obj1, obj2);
console.log(result1);
// => { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 }

const obj3    = { a: 1, b: 2, c: 3 };
const obj4    = { a: 4 };
const result2 = Object.assign(obj3, obj4);
console.log(result2);
// 同じKeyの値がある場合、第2引数のものに上書きされる
// => { a: 4, b: 2, c: 3 }

スプレッド構文を使用した方法

@shiracamus 様にコメントで教えていただきました、ありがとうございます。

const obj1    = { a: 1, b: 2, c: 3 };
const obj2    = { d: 4, e: 5, f: 6 };
const result1 = { ...obj1, ...obj2 }
console.log(result1);
// => { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 }

const obj3    = { a: 1, b: 2, c: 3 };
const obj4    = { a: 4 };
const result2 = { ...obj3, ...obj4 }
console.log(result2);
// 同じKeyの値がある場合、2つ目のものに上書きされる
// => { a: 4, b: 2, c: 3 }

参考

多重Dictionaryをつくりたかった

C#は素人なので定石がわかりません。

こういう連想配列があったとしましょう。

PHP
$datetimes = [
    'past' => [
        'yesterday' => new DateTime('yesterday'),
        'lastweek' => new DateTime('last week'),
    ],
    'future' => [
        'tomorrow' => new DateTime('tomorrow'),
        'nextyear' => new DateTime('next year'),
    ]
];

いや、こんな意味のわからない配列なんて作らねえよという抗議は全くもってその通りなのですがそこはスルーします。
実際はAPIに飛んできたリクエストをユーザ単位にまとめるみたいな処理をするところで、何個飛んでくるかわからないという仕様です。

PHPで書くとこんな感じでさくっとできます。

PHP
$datetimes = [];
foreach($request as $v){
    $datetimes[$v['tense']][$v['key']] = new DateTime($v['value']);
}

一瞬で書けてとってもらくちん。

ということで、この連想配列をC#に移植しようとしたのですが、どうもこのような構造について話をしているところがほとんど見当たりませんでした。
多重連想配列はC#では禁忌なのだろうか。

連想配列はDictionaryを使えばいいみたいですが、これは基本的に値がひとつです。
NameValueCollectionというのが目的に近かったのですが、これは値がstring固定みたいです。なぜ。
Microsoft.Experimental.Collectionsは名前が既に危ない。

試しにDictionaryの中にDictionaryを突っ込んでみたら普通にいけました。

    var datetimes = new Dictionary<string, Dictionary<string, DateTime>>();

    var list1 = new Dictionary<string, DateTime>();
    list1.Add("yesterday", new DateTime("yesterday"));
    list1.Add("lastweek", new DateTime("last week"));

    var list2 = new Dictionary<string, DateTime>();
    list2.Add("tomorrow", new DateTime("tomorrow"));
    list2.Add("nextyear", new DateTime("next year"));

    datetimes.Add("past", list1);
    datetimes.Add("future", list2);

ただ、この構造だとlist1などの中間変数が必要になってしまいます。
一気にdatetimes["past"].Add("yesterday", new DateTime("yesterday"));みたいなことはできないの?

    var datetimes = new Dictionary<string, Dictionary<string, DateTime>>();

    // The given key "past" was not present in the dictionary
    datetimes["past"].Add("yesterday", new DateTime("yesterday"));

    // Object reference not set to an instance of an object
    datetimes.Add("past", null);

    // An item with the same key has already been added
    datetimes.Add("past", new Dictionary<string, DateTime>{{"yesterday", new DateTime("yesterday")}} );
    datetimes.Add("past", new Dictionary<string, DateTime>{{"lastweek", new DateTime("last week")}} );

    // これはOK
    datetimes.Add("past", new Dictionary<string, DateTime>{{"yesterday", new DateTime("yesterday")}} );
    datetimes["past"].Add("lastweek", new DateTime("last week"));

Add自体はできるみたいですが、親Dictionaryのキーの有無によって動作を変えなければなりません。
キーが存在しない場合のみキーをAddし、その後はその中身だけAddしないといけないようです。
なんというかとても面倒。

もっとなんかマシな方法ってのがあるんだろうけどよくわかりませんでした。
そもそもC#ではどういう作りにするのが定石なんだろうか。

JavaScriptでBibTeXを連想配列に分解

BibTeXを連想配列に分解するスクリプトを書きました。

BibTeXとは?

$\TeX$で文献を引用する際に利用するツールです。
GoogleScholarからデータをコピペで持ってくる事ができるなど、便利な点が色々あります。
BibTeXについては以下がとても参考になります。
- BiBTeXとは
- Texで書く論文の引用にはbibtexがオススメな4つの理由

背景

Google Spread Sheetで論文を整理しようとした際、「BibTeXの項目で分解できれば表の管理ラクじゃないか?」と思ったことがキッカケです。
ということで、BibTeX形式を分解することにしました。

スクリプト

元々はGAS(Google App Script)のために書いたものですが、互換性があるJavaScriptとして記載します。

resoluteBibtex.js
functionresoluteBibtex(bibtex_source){// BibTeXソースを要素ごとの連想配列に分解varbibtex_source_tailcut=bibtex_source.replace(/}[\n]*}/,'');// 末尾の'} }'を削除varbibtex_splited=bibtex_source_tailcut.split(/},[\n]*/);varbibtex_contents={};varvalue,value_splited;for(varindexinbibtex_splited){value=bibtex_splited[index];// @xxxxx{label, となっている部分の対応if(value.charAt(0)=='@'){value_splited=value.split('{');bibtex_contents['@']=value_splited[0];bibtex_contents['label']=value_splited[1].substring(0,value_splited[1].indexOf(','));varnext_content_by_label=value_splited[1].replace(/[\w]*, */,'');bibtex_contents[next_content_by_label.replace('=','')]=value_splited[2];}else{value_splited=value.split('={');bibtex_contents[value_splited[0]]=value_splited[1];}}returnbibtex_contents;}

使用例

入力:BibTeX形式のデータ
出力:連想配列

// BibTeX形式のデータvarbibtex_source="@inproceedings{shvachko2010hadoop,
  title={The hadoop distributed file system.},
  author={Shvachko, Konstantin and Kuang, Hairong and Radia, Sanjay and Chansler, Robert and others},
  booktitle={MSST},
  volume={10},
  pages={1--10},
  year={2010}
}";varbibtex_contents=resoluteBibtex(bibtex_source);

実行結果

変数bibtex_contentsの中身は以下のようになっています。

// キー:値 で表示"@":"inproceedings","label":"shvachko2010hadoop","title":"The hadoop distributed file system.","author":"Shvachko, Konstantin and Kuang, Hairong and Radia, Sanjay and Chansler, Robert and others","booktitle":"MSST","volume":"10","pages":"1--10","year":"2010"

titleauthorといった項目名は上記の例以外でも対応しています。

まとめ

BibTeX形式を連想配列に分解するスクリプトを書きました。
JavaScriptやGoogle App ScriptでBibTeXを扱う場合にご利用ください。

Vue.jsで連想配列を使おう!

🍪Vue.jsで連想配列を使おう!

はじめまして、s4na🐧と申します。
今回はじめてQiitaの記事を書きます。

今回書く内容は、少し前にVue.jsで実装していたら躓いた連想配列の利用方法です。
一時期は「計算量が増えるけど、連想配列を使わないで実装してしまおうかな・・・😢」と思ったこともあるくらい大きく躓きました。

少しでも私と同じところで躓く人の力になればと思い、今回筆をとりました。🖋

RailsのViewからVue.jsに連想配列を渡す方法

まずはRailsのViewからVue.jsに連想配列を渡す方法について書いていきます。

この方法は、Rails側からVue.jsに初期値を渡す際に使います。
もちろん、APIを作ってそちらで渡してもいいのですが、それだとAPI分の通信量が増えてしまうので、私はViewから渡しています。

  • 補足:RailsのView = MVCのView

ControllerでJSON化しておく

  • 補足:Hashのまま渡すと、Vue.jsがParseできないです。フロントで無理にパースしてもいいのかもしれませんが、サーバーサイドでできることはサーバーサイドでしたほうが良さそうです
@foo=JSON(foo)

View

  • 補足:
    • RailsのTemplate Engineはslimで書いています
    • @foo, @baaみたいに値を複数渡す場合もあるので、#js-el-data-fooのように名前を区切ると便利です。
#js-el#👈Vue.jsがマウントするDOM
  #js-el-data-foo=@foo# 👈渡したい値 その1#js-el-data-baa=@baa# 👈渡したい値 その2

Vueインスタンス

Vue.js側では、ViewのDOMのinnerTextを取得し、JSON化してdataに入れ込みます。

<script>exportdefault{data:()=>{return{reservations:{}}},created:function(){//                 👇JSONが連想配列になる                            👇JSONで受け取るthis.memos=JSON.parse(document.querySelector('#js-el-data-foo').innerText);}}</script>

Vueインスタンスで連想配列をループ表示する方法

連想配列の表示は連想配列[key]とする必要があり、そのためにはkeyの集合であるkeysが必要になります。

  • 補足:テンプレートエンジンにはPugを使用しています
<templatelang="pug">.foo(v-for="key in keys")|{{foo[key]}}</template>
<script>exportdefault{data:()=>{return{reservations:{},keys:[]}}}</script>

Vueインスタンス内で連想配列に情報を追加する方法

追加する際は$setメソッドを使いましょう。

これは書こうとした時、めっちゃハマりました。😭
この記事を書こうと思った原点でもあります。

他の言語やフレームワークを利用していたりすると、「val['key']で値を代入できるのでは?」と考えてしまうこともあるかと思います。(私はそうでした。)

Vue.jsでは、JavaScriptの仕様で、連想配列に要素を追加した時に検知できません。
なので、変更検出が可能なメソッドを利用する必要があります。(公式ドキュメントを読めば気づけるけど、読んでなかった😈)

Vue.js#オブジェクトの変更検出の注意

exportdefault{data:()=>{return{foo:{}}},methods:{addFoo:function(key,hoge){this.$set(this.foo,`key`,hoge);}}

連想配列から要素を削除する方法

削除する際は$deleteメソッドを使いましょう。
JavaScriptを書いていると、deleteメソッドで削除してしまったりすることがあると思います。(私はそうでした)
それだと$setと同様に、Vue.jsが要素数の変化を検知できないので、$deleteを使う必要があります。

methods:{deleteFoo:function(key){this.$delete(this.foo,key);}}

Vueインスタンスで連想配列をAPIで取得する方法

methods:{token(){constmeta=document.querySelector('meta[name="csrf-token"]')returnmeta?meta.getAttribute('content'):''},getFoo:function(){fetch(`/api/hogehoge`,{method:'POST',headers:{'Content-Type':'application/json; charset=utf-8','X-Requested-With':'XMLHttpRequest','X-CSRF-Token':this.token()},credentials:'same-origin',redirect:'manual',}).then(response=>{returnresponse.json();}).then(json=>{this.$set(this.foo,`key`,json);// 👈受け取った値を連想配列`foo`に入れる}).catch(error=>{console.warn('Failed to parsing',error);})},

まとめ

  • Vue.jsで連想配列を扱うのは、癖がわかれば結構簡単!
  • 時間がなくて厳しくても、触ったことのない技術を触るのであれば、何よりもまずは公式ドキュメントを全部読もう!!!
  • Vue.jsならこちらのガイドを読もう!!!

プログラミング初心者の配列のまとめ

今週は制作物を投稿するつもりでしたが、忘備録として投稿したい内容があるのでそっちを先に。

プログラミング学習始めて2ヶ月。JSとPHPを学んできました。
そこでずっとずっとずっと悩みの種の一つが配列
JS時もイマイチで、その後PHPの勉強をしたのですが、ここでも出てくる配列。
今回課題作成にあたり相当配列を使ったので、忘れないよう忘備録として書きます。

当たり前と言えば当たり前の事なんですが、私はここまでたどり着くのに2ヶ月・・・
そして正直まだ全部理解したとも思えず・・・自信はありません。

まず普通の配列

letarray=["name","id","pw","emal"];//配列の長さを取得console.log(array.length);//4//配列の1個目を取得console.log(array[1]);//"name"//"pw"が配列内の何個目にあるか知りたいconstresult=$.inArray("pw",array);console.log(result);//2

次に連想配列
連想配列はkey:valueで成り立っている

letarary={name:"鈴木",id:"1111",pw:"aaaa",email:"test@test.com"}//配列内のkey名取得constkey=Object.keys(array);console.log(key);//["name", "id", "pw", "email"]//nameというkeyのvalueを取得console.log(array.name);//"鈴木"

最後に多次元の連想配列、普通の配列+連想配列のイメージ

letarray=[{name:"鈴木",id:"1111",pw:"aaaa",email:"test@test.com"},{name:"田中",id:"2222",pw:"bbbb",email:"test2@test2.com"},{name:"佐藤",id:"3333",pw:"cccc",email:"test3@test3.com"}];// 多次元配列内の1番目の連想配列を取得console.log(array[1]);//{name: "田中", id: "2222", pw: "bbbb", email: "test2@test2.com"}// 取得した連想配列の"name"keyのvalueを取得console.log(arryB[1].name);//"田中"

今思い返すと「配列苦手!」と感じていた要因としては、
大体何か作っていて配列使う時はループ処理が伴う事が多かった。
私はまだまだプログラミング脳ではないためループ処理はループ処理でよくわからんかったし(回すって何!?というレベルでした)、その上イメージがつかない配列があってぐちゃぐちゃ。
例えばこういうの

letarray=[{name:"鈴木",id:"1111",pw:"aaaa",email:"test@test.com"},{name:"田中",id:"2222",pw:"bbbb",email:"test2@test2.com"},{name:"佐藤",id:"3333",pw:"cccc",email:"test3@test3.com"}];// 多次元配列のキーを取得letkeyB=Object.keys(arryB);console.log(keyB);// ["0", "1", "2"]for(vari=0;i<key.length;i++){letall=(array[i])//多次元配列内の全ての連想配列を取得console.log(all);//取得した連想配列の"id"keyのvalueを取得console.log(all["id"]);//"1111","2222","3333"}

 JSだけの時はこればっかりで訳わからなかったのですが、個人的にはPHPも勉強してデータを扱うようになって、[配列]とループ処理が少しずつわかってきたかも!?って感じです。

GASのデバッグモードで、連想配列に空欄があると、デバッガーにはその要素が表示されないメモ

連想配列にあるべきキーと要素(空欄)が確認できない???

GASのデバッグモードでブレークポイントを使って各変数の状態を確認するなんてことはよくあると思いますが
連想配列にセットした値が空欄('')のような場合は、プロパティエリアには表示されなかったのでメモします。

test.gs
varlist={'mango':100,'orange':200,'apple':'','pineapple':'pen'};varbreakPoint=1;//←ここでブレイクポイントを打つ

デバッグモードで実行した結果、以下のようにappleは表示されない。
image.png

他のIDEもこれが普通?大層な開発環境使ってないのでわかりませんが
これだけのことで2時間ぐらいハマりました…

PHP 配列に連想配列を入れる

目的

  • 配列の中に連想配列を入れる方法をまとめる

実施環境

  • MacOS上のローカル環境にテスト用スクリプトファイルを作成してVisual Studio Codeのデバッグを用いて結果を確認した。
  • 下記にVisual Studio CodeでPHPのデバッグ環境を構築する際の手順をまとめた記事へのリンクを記載する。
  • 下記に実施環境の詳細な情報を記載する。
項目情報
OSmacOS Catalina(10.15.3)
ハードウェアMacBook Air (11-inch ,2012)
プロセッサ1.7 GHz デュアルコアIntel Core i5
メモリ8 GB 1600 MHz DDR3
グラフィックスIntel HD Graphics 4000 1536 MB

PHPの配列の書き方

PHPの連想配列の書き方

書き方の例(配列を連想配列に格納する)

  • 下記に配列$testに連想配列('num1' => 10, 'num2' => 20, 'num3' => 30)を格納する方法をまとめる。
  • 下記が実行されると配列$test[0]には'num1' => 10, 'num2' => 20, 'num3' => 30の連想配列が格納される。

    $test=[['num1'=>10,'num2'=>20,'num3'=>30]];

書き方の例(配列に入った連想配列を出力する)

  • 先の「書き方の例(配列を連想配列に格納する)」のコードを引き継いで説明する。
  • 配列名[インデックス番号][連想配列のキー]と言うように指定することで格納された値を得ることができる。
  • 配列$testのnum1~num3の値を出力したい時の例を下記に記載する。

    $test=[['num1'=>10,'num2'=>20,'num3'=>30]];#---これより上は「書き方の例(配列を連想配列に格納する)」のコードと一緒---## num1を出力するecho$test[0]['num1'];# num2を出力するecho$test[0]['num2'];# num3を出力するecho$test[0]['num3'];

書き方の例(配列に入った連想配列の末尾にデータを追加する)

  • 先の「書き方の例(配列を連想配列に格納する)」のコードを引き継いで説明する。
  • array_push(配列名,末尾に追加するデータと言うように指定することでデータを追加することができる。
  • 下記に配列$testの末尾に連想配列('num1' => 40, 'num2' => 50, 'num3' => 60)を格納する方法をまとめる。

    $test=[['num1'=>10,'num2'=>20,'num3'=>30]];#---これより上は「書き方の例(配列を連想配列に格納する)」のコードと一緒---#array_push($test,['num1'=>40,'num2'=>50,'num3'=>60]);

HaskellのMap型、Set型

概要

多くのプログラミング言語でよく利用されMap型(ハッシュ型、キーバリュー型、辞書型、連想配列とも言われる)と、集合演算でよく使われるSet型をHaskellではどのように扱うかをいくつかのケースごとに紹介します。
Haskellでは標準関数としてMap型やSet型が実装されていないため、containersパッケージを事前にinstallする必要があります。

特徴

Map型、Set型は一般的にハッシュテーブルを用いて実装されている場合が多いがHaskellでは平衡二分木で実装されているため、データ構造の操作に関する計算量が異なる。

ハッシュテーブル平衡二分木
取得O(1)O(logN)
 削除  O(1)O(logN)
挿入O(1)O(logN)

計算量ではよく使われるハッシュテーブルに劣る反面、HaskellのMap型、Set型には数多くの強力な関数が用意されており、key-valueの順序関係も保持できるため、リストを扱うよう操作できる点がとても魅力的である。
HaskellのMapのベンチマーク結果はこちらを参照

参考資料

Data.Map-Hackage
Data.Set-Hackage

※本記事では上記の二つの記事の中から利用ケース別にいくつかピックアップして紹介するため、いくつか省いている機能(Map型における集合関数、本記事で載せている関数の類似関数など)が多数あります。より多くの関数や各種関数の計算量を知りたい方やは上記を参照してください。

version

containers >= 0.5.9

本記事では0.6.2.1を扱う。

準備

初めにそれぞれのパッケージをインポートします。

sample.hs
importqualifiedData.Map.StrictasMimportqualifiedData.SetasS

呼び出しの簡略化のため、ここではMap型をM、Set型をSとして利用します。
またimport qualified Data.Mapもありますが、特別な理由がなければData.Map.Strictを使うことが推奨されているようです。

Data.Mapドキュメントの先頭行を抜粋

Note: You should use Data.Map.Strict instead of this module if:

  • You will eventually need all the values stored.
  • The stored values don't represent large virtual data structures to be lazily computed.

An efficient implementation of ordered maps from keys to values (dictionaries).

qualifiedはPreludeの標準の関数と名前の衝突を避けるために使用します。

Map型

importqualifiedData.Map.StrictasM

以降、Map型がインポートされていることを前提に記述する。

使用するデータセット

fruits::[(String,Int)]fruits=[("apple",1),("orange",2),("banana",3),("peach",4),("cherry",5),("orange",6),("apple",7),("peach",8)]fruitsMap=M.fromListfruits
ghci環境での実行結果
PreludeM>fruits[("apple",1),("orange",2),("banana",3),("peach",4),("cherry",5),("orange",6),("apple",7),("peach",8)]PreludeM>fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("orange",6),("peach",8)]

Haskellでは既存の型からMap型を生成する場合、タプル型のリストが用いられ、fstの値がkey,sndの値がvalueに対応してMap型が生成される。Map型の生成にはfromListが用いられる。

fromListの定義
fromList::Ordk=>[(k,a)]->Mapka

定義より、fstが比較可能な型で、2つの値を持つタプル型であれば変換可能であることがわかる。
また、変換時にfstが重複する場合、最後に表れたfstをkey,その値をvalueとした要素のみが残る。
※例ではfruitsに存在していた、("apple",1)("apple",7)("peach",4)("peach",8)のうち、後の("apple",7)("peach",8)のみが残っていることを表している。
同じキーが複数回表れた場合、何らかの処理を適用して前に表れた値についても利用する方法については後述する。
変換時はkeyで昇順ソートされてMap型に変換される。
※fromListの他にも昇順リスト、降順リストなど変換前のリストの状態に応じたMap型への変換関数が用意されているので、詳細はこちらを参照してください。

空Mapの表現(empty)

Data.Mapより抜粋
empty::Mapka
ghci環境での実行結果
PreludeMMain>M.fromList[]==M.emptyTruePreludeM>M.fromList[("orange",3)]==M.emptyFalse

単一要素を持ったMapの表現(singleton)

Data.Mapより抜粋
singleton::k->a->Mapka
ghci環境での実行結果
PreludeM>M.singleton"peach"4==M.fromList[("peach",4)]TruePreludeM>M.singleton"peach"4==M.fromList[("peach",4),("oraneg",3)]False

データの参照(lookup,!?,!)

手続き型言語におけるMap.get(key)Map[key]に相当する操作。

Data.Mapより抜粋
lookup::Ordk=>k->Mapka->Maybea
ghci環境での実行結果
PreludeMMain>fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("orange",6),("peach",8)]PreludeMMain>M.lookup"orange"fruitsMapJust6PreludeMMain>M.lookup"beef"fruitsMapNothing
Data.Mapより抜粋
(!?)::Ordk=>Mapka->k->Maybea
ghci環境での実行結果
PreludeMMain>fruitsMapM.!?"orange"Just6PreludeMMain>fruitsMapM.!?"beef"Nothing
Data.Mapより抜粋
(!)::Ordk=>Mapka->k->a
ghci環境での実行結果
PreludeMMain>fruitsMapM.!"orange"6PreludeMMain>fruitsMapM.!"beef"***Exception:Map.!:givenkeyisnotanelementinthemapCallStack(fromHasCallStack):error,calledatlibraries/containers/containers/src/Data/Map/Internal.hs:627:17incontainers-0.6.2.1:Data.Map.Internal

lookup!?はキーが存在しないことを考慮しているのに対し、!は直接の値を取得しているため、存在しないときはエラーとなる

データの追加(insert)

手続き型言語におけるMap.set(key,value)Map[key]=valueに相当する操作。

Data.Mapより抜粋
insert::Ordk=>k->a->Mapka->Mapka
ghci環境での実行結果
PreludeM>fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("orange",6),("peach",8)]PreludeMMain>M.insert"grape"1fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("grape",1),("orange",6),("peach",8)]PreludeMMain>M.insert"orange"1fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("orange",1),("peach",8)]PreludeMMain>M.insert"kiwi"10emptyfromList[("kiwi",10)]

データの挿入はkeyの昇順ソート順で適切な位置に挿入される。すでに存在しているキーに対してinsertした場合は新しいkey,valueで上書きされる。

データの削除(delete)

Data.Mapより抜粋
delete::Ordk=>k->Mapka->Mapka
ghci環境での実行結果
PreludeMMain>fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("orange",6),("peach",8)]PreludeMMain>M.delete"orange"fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("peach",8)]PreludeMMain>M.delete"beef"fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("orange",6),("peach",8)]

存在しないものを削除しようとした場合は、そのままのMapを返す。

データの存在チェック(member)

手続き型言語におけるMap.has(key)に相当する操作。

Data.Mapより抜粋
member::Ordk=>k->Mapka->Bool
ghci環境での実行結果
PreludeMMain>fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("orange",6),("peach",8)]PreludeMMain>M.member"orange"fruitsMapTruePreludeMMain>M.member"beef"fruitsMapFalse

memberはkeyが存在する場合はTrue,存在しない場合はFalseを返す。

データ値の更新(update)

Data.Mapより抜粋
update::Ordk=>(a->Maybea)->k->Mapka->Mapka
ghci環境での実行結果
PreludeM>fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("orange",6),("peach",8)]PreludeM>M.update(\x->Just(x+100))"cherry"fruitsMapfromList[("apple",7),("banana",3),("cherry",105),("orange",6),("peach",8)]PreludeM>M.update(\x->Just(x+100))"beef"fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("orange",6),("peach",8)]

insertによる更新との違いは現在設定しているvalueを元に適用する操作を変えることができる。

keyリストの取得(keys)

Data.Mapより抜粋
keys::Mapka->[k]
ghci環境での実行結果
PreludeMMain>fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("orange",6),("peach",8)]PreludeMMain>M.keysfruitsMap["apple","banana","cherry","orange","peach"]

これはお馴染みの書き方。

valueリストの取得(elems)

Data.Mapより抜粋
elems::Mapka->[a]
ghci環境での実行結果
PreludeMMain>fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("orange",6),("peach",8)]PreludeMMain>M.elemsfruitsMap[7,3,5,6,8]

リストへの変換(toList)

Data.Mapより抜粋
toList::Mapka->[(k,a)]
ghci環境での実行結果
PreludeM>fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("orange",6),("peach",8)]PreludeM>toListfruitsMap[("apple",7),("banana",3),("cherry",5),("orange",6),("peach",8)]

toAscListtoDescListを使えばソートも可能

キー、バリューリスト<(k,[a])型>(fromListWith)への変換

Data.Mapより抜粋
fromListWith::Ordk=>(a->a->a)->[(k,a)]->Mapka
ghci環境での実行結果
PreludeM>fruits[("apple",1),("orange",2),("banana",3),("peach",4),("cherry",5),("orange",6),("apple",7),("peach",8)]PreludeM>M.fromListWith(++)$map(\(k,v)->(k,[v]))fruitsfromList[("apple",[7,1]),("banana",[3]),("cherry",[5]),("orange",[6,2]),("peach",[8,4])

fromListWithではMap型生成時にlambdaを渡せるため、keyが重複した場合の挙動を記述できる

重複したキーの値の和を求めたい場合には以下のようにも書ける

Data.Mapより抜粋
PreludeM>M.fromListWith(+)fruitsfromList[("apple",8),("banana",3),("cherry",5),("orange",8),("peach",12)]

高階関数の適用(map,foldl,filter)

Data.Mapより抜粋
map::(a->b)->Mapka->MapkbmapKeys::Ordk2=>(k1->k2)->Mapk1a->Mapk2afoldl::(a->b->a)->a->Mapkb->a
ghci環境での実行結果
PreludeM>fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("orange",6),("peach",8)]PreludeM>M.map(+1)fruitsMapfromList[("apple",8),("banana",4),("cherry",6),("orange",7),("peach",9)]PreludeM>M.mapKeys("F."++)fruitsMapfromList[("F.apple",7),("F.banana",3),("F.cherry",5),("F.orange",6),("F.peach",8)]PreludeM>M.foldl(+)0fruitsMap29PreludeM>M.foldlWithKey(\acckv->acc++(k++"="++showv))[]fruitsMap"apple=7banana=3cherry=5orange=6peach=8"PreludeM>M.filter(>5)(fruitsMap)fromList[("apple",7),("orange",6),("peach",8)]PreludeM>M.filterWithKey(\x_->lengthx>5)fruitsMapfromList[("banana",3),("cherry",5),("orange",6)]

リストで用意されているようなmap,foldl,foldr,filterがMap型にもそのまま適用できる。
key,value,またはその両方に適用できるような関数が各種に用意されている。

サイズを取得する(size)

Data.Mapより抜粋
size::Mapka->Int
ghci環境での実行結果
PreludeM>fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("orange",6),("peach",8)]PreludeM>M.sizefruitsMap5

keyの最小、最大を取得(lookupMax,lookupMin,findMax,findMin)

Data.Mapより抜粋
lookupMin::Mapka->Maybe(k,a)lookupMax::Mapka->Maybe(k,a)findMin::Mapka->(k,a)findMax::Mapka->(k,a)
ghci環境での実行結果
PreludeM>fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("orange",6),("peach",8)]PreludeM>M.lookupMinfruitsMapJust("apple",7)PreludeM>M.lookupMaxfruitsMapJust("peach",8)PreludeM>M.lookupMaxM.emptyNothingPreludeM>M.findMinfruitsMap("apple",7)PreludeM>M.findMaxfruitsMap("peach",8)PreludeM>M.findMaxM.empty***Exception:Map.findMax:emptymaphasnomaximalelementCallStack(fromHasCallStack):error,calledatlibraries/containers/containers/src/Data/Map/Internal.hs:1672:17incontainers-0.6.2.1:Data.Map.Internal

valueに対して最小、最大を取ってくるものは残念ながら存在しないため、事前にimport Data.turple (swap)を用いて、key-valueを入れ替えておく必要がありそう。これはおそらく、Map型の定義より、valueには順序付きの制約(Ord)がないためだと思われる。

keyからIndexを取得(lookupIndex,findIndex)

Data.Mapより抜粋
lookupIndex::Ordk=>k->Mapka->MaybeIntfindIndex::Ordk=>k->Mapka->Int
ghci環境での実行結果
PreludeM>fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("orange",6),("peach",8)]PreludeM>M.lookupIndex"cherry"fruitsMapJust2PreludeM>M.lookupIndex"beef"fruitsMapNothingPreludeM>M.findIndex"cherry"fruitsMap2PreludeM>M.findIndex"beef"fruitsMap***Exception:Map.findIndex:elementisnotinthemapCallStack(fromHasCallStack):error,calledatlibraries/containers/containers/src/Data/Map/Internal.hs:1457:23incontainers-0.6.2.1:Data.Map.Internal

keyを指定することで、その要素のindexを取得する。ハッシュテーブルで実装されたMapには順序関係は存在しないため、HaskellにおけるMap型ならでは機能である。

indexから要素(key-value)を取得(elemAt)

Data.Mapより抜粋
elemAt::Int->Mapka->(k,a)
ghci環境での実行結果
PreludeM>fruitsMapfromList[("apple",7),("banana",3),("cherry",5),("orange",6),("peach",8)]PreludeM>M.elemAt0fruitsMap("apple",7)PreludeM>M.elemAt3fruitsMap("orange",6)PreludeM>M.elemAt5fruitsMap***Exception:Map.elemAt:indexoutofrangeCallStack(fromHasCallStack):error,calledatlibraries/containers/containers/src/Data/Map/Internal.hs:1498:17incontainers-0.6.2.1:Data.Map.Internal

指定したindexに対応する要素をMapから取得する。ハッシュテーブルで実装されたMapには順序関係は存在しないため、HaskellにおけるMap型ならでは機能である。

Set型

importData.SetasS

以降、Set型がインポートされていることを前提に記述する

使用するデータセット

universeOne=["comet","earth","jupiter","mars","venus","mars","venus"]universeTwo=["star","jupiter","meteor","comet","planet"]universeOneSet=S.fromListuniverseOneuniverseTwoSet=S.fromListuniverseTwo

Map型と同様、fromListを用いることでSet型に変換でき、変換時に昇順ソートされる。

PreludeS>universeOne["comet","earth","jupiter","mars","venus","mars","venus"]PreludeS>universeOneSetfromList["comet","earth","jupiter","mars","venus"]

基本的な操作に対する関数名はMap型とほとんど同じものであるが、Set型についてもケース別に記載する

空Setの表現(empty)

Data.Setより抜粋
empty::Seta
ghci環境での実行結果
PreludeS>S.empty==S.fromList[]True

単一要素を持ったSetの表現(singleton)

Data.Setより抜粋
singleton::a->Seta
ghci環境での実行結果
PreludeS>S.singleton"comet"==S.fromList["comet"]True

データの追加(insert)

Data.Setより抜粋
insert::Orda=>a->Seta->Seta
ghci環境での実行結果
PreludeS>universeOneSetfromList["comet","earth","jupiter","mars","venus"]PreludeS>S.insert"cosmos"universeOneSetfromList["comet","cosmos","earth","jupiter","mars","venus"]

データの削除(delete)

Data.Setより抜粋
delete::Orda=>a->Seta->Seta
ghci環境での実行結果
PreludeS>universeOneSetfromList["comet","earth","jupiter","mars","venus"]PreludeS>S.delete"mars"universeOneSetfromList["comet","earth","jupiter","venus"]

データの存在チェック(member)

Data.Setより抜粋
member::Ordk=>k->Mapka->Bool
ghci環境での実行結果
PreludeS>universeOneSetfromList["comet","earth","jupiter","mars","venus"]PreludeS>S.member"jupiter"universeOneSetTruePreludeS>S.member"cosmos"universeOneSetFalse

リストへの変換(toList)

Data.Setより抜粋
toList::Seta->[a]
ghci環境での実行結果
PreludeS>universeOneSetfromList["comet","earth","jupiter","mars","venus"]PreludeS>S.toListuniverseOneSet["comet","earth","jupiter","mars","venus"]

サイズを取得する(size)

Data.Setより抜粋
size::Seta->Int
ghci環境での実行結果
PreludeS>universeOneSetfromList["comet","earth","jupiter","mars","venus"]PreludeS>S.sizeuniverseOneSet5

高階関数(map,filter,foldl)

Data.Setより抜粋
map::Ordb=>(a->b)->Seta->Setbfilter::(a->Bool)->Seta->Setafoldl::(a->b->a)->a->Setb->a
ghci環境での実行結果
PreludeS>S.map(\x->"U."++x)universeOneSetfromList["U.comet","U.earth","U.jupiter","U.mars","U.venus"]PreludeS>S.filter(\x->lengthx==5)universeOneSetfromList["comet","earth","venus"]PreludeS>S.foldl(++)[]universeOneSet"cometearthjupitermarsvenus"

Map型と同様にリストのように高階関数が取り扱える。

集合演算(union,difference,intersection)

Data.Setより抜粋
union::Orda=>Seta->Seta->Setadifference::Orda=>Seta->Seta->Setaintersection::Orda=>Seta->Seta->Seta
ghci環境での実行結果
PreludeS>universeOneSetfromList["comet","earth","jupiter","mars","venus"]PreludeS>universeTwoSetfromList["comet","jupiter","meteor","planet","star"]PreludeS>S.unionuniverseOneSetuniverseTwoSetfromList["comet","earth","jupiter","mars","meteor","planet","star","venus"]PreludeS>S.differenceuniverseOneSetuniverseTwoSetfromList["earth","mars","venus"]PreludeS>S.intersectionuniverseOneSetuniverseTwoSetfromList["comet","jupiter"]

union、difference、intersectionはそれぞれ二つの集合の和集合、差集合、積集合した結果を返す。

部分集合かどうかチェック(isSubsetOf)

Data.Setより抜粋
isSubsetOf::Orda=>Seta->Seta->Bool
ghci環境での実行結果
PreludeS>universeOneSetfromList["comet","earth","jupiter","mars","venus"]PreludeS>S.isSubsetOf(S.fromList["mars","earth"])universeOneSetTruePreludeS>S.isSubsetOf(S.fromList["mars","cosmos"])universeOneSetFalsePreludeS>S.isSubsetOfS.emptyuniverseOneSetTruePreludeS>S.isSubsetOfS.emptyS.emptyTruePreludeS>S.isSubsetOfuniverseOneSetuniverseOneSetTrue

isSubsetOfisSubsetOf A Bに対してAがBの部分集合である場合はTrue,そうでない場合はFalseを返す。

終わりに

本記事ではHaskellにおけるMap型、Set型で用意されている操作関数の中で、手続き型言語でもお馴染みの操作パターンを例にいくつか紹介しました。HaskellではMap型を用いるような操作はTurple型リストで解決できる場合が多いので、出番があるかどうかは作り手次第によると思いますが、Map型を利用する場合の名前確認表に本記事をご利用頂ければと思います。Map型を利用する場合は基本操作に対する計算量がO(1)ではなくO(logN)であること(操作によってはO(N)やO(NlogN)のものもあります)を十分考慮して設計してください。
また、公式ドキュメントには本記事で載せなかった亜種が多数存在しますので、よりニッチな利用ケースには参考資料の公式ページをご利用ください。

【PHP】連想配列の特定の要素を取り出す

GW前ですが超初心者向けにちょっとした配列操作を書きます。

Array
(
    [0] => TESTArray Object
        (
            [name] => math

            [count] => 5

        )
    [1] => TESTArray Object
        (
            [name] => history

            [count] => 10

        )
    [2] => TESTArray Object
        (
            [name] => science

            [count] => 20

        )

)

上の配列から
科目(name)が歴史だった場合、歴史の人数(count)を取得する
コードをForeachを使用して書くと

 foreach($arr as $i) {
    if($i->name == "history") return $i->count;
}

こうゆう書き方もあり?

  foreach($ayy as $i) {
    if($i->name !== "history") continue;
    return $i->count;
  }

連想配列を説明する

じゃあまずC#で書く。

ex.cs
usingSystem;usingSystem.Collections.Generic;publicclassEx{publicstaticvoidMain(){varjcpmusicdotcom=newDictionary<string,string>();jcpmusicdotcom["東方ロストワード"]="ロストワードクロニカル";jcpmusicdotcom["俺はボーマンダ"]="レプリカの恋";jcpmusicdotcom["ほのぼの神社"]="SHAMAN QUEEN";foreach(varmusicinjcpmusicdotcom){Console.WriteLine($"{music.Value}は、{music.Key}を連想する音楽です。");}}}

次にPythonで書いてみる。

ex.py
classEx:defmain():jcpmusicdotcom={}jcpmusicdotcom["東方ロストワード"]="ロストワードクロニカル"jcpmusicdotcom["俺はボーマンダ"]="レプリカの恋"jcpmusicdotcom["ほのぼの神社"]="SHAMAN QUEEN"formusickeyinjcpmusicdotcom:print(f"{jcpmusicdotcom[musickey]}は、{musickey}を連想する音楽です。")if__name__=="__main__":Ex.main()

やはりどちらもC言語の影響があるので大して書き方が変わらないですね。私は、結構C#とかPythonとかの「汚い書き方ができないスタイル」が好きなのですが、皆さんはどうですか?コメントよろしくお願いします。

〔JavaScript〕連想配列の使い方

連想配列とは

JavaSciptには連想配列というものがあります。

  • 連想配列では、1つの変数で複数の「キー」と「を保持できます。
  • キーは任意の文字列を使うことができます。
  • 各項目をプロパティと呼びます。(キーのことをプロパティとも呼びます)
  • 構文は、キーと値を波括弧{}でくくります。(項目が複数の場合はカンマで区切ります。)
  • 連想配列はオブジェクトリテラルまたはハッシュとも呼ばれます。
  • 配列のarrayオブジェクトを継承していません。(arrayオブジェクトのメソッドやプロパティは使えません)

宣言の仕方

consta={};// またはconsta=newObject();// で連想配列を宣言する

とすることで宣言することができます。
サンプルを作ってみます。

constanimals={a1:"",a2:"",a3:""};console.log(animals["a1"]);// 犬console.log(animals["a2"]);// 猫console.log(animals["a3"]);// 鳥

その他の使い方を例で説明していきます。

項目を追加する方法

constanimals={a1:"",a2:"",a3:""};animals["a4"]="";console.log(animals);//{a1:"犬",a2:"猫",a3:"鳥",a4 :"熊"};

4つ目に追加することができました。

項目を更新する

constanimals={a1:"",a2:"",a3:""};animals["a2"]="";console.log(animals);//{a1:"犬",a2:"猿",a3:"鳥"};

既にあるキーの値を更新することができました。

項目を削除する

constanimals={a1:"",a2:"",a3:""};deleteanimals["a2"];console.log(animals);//{a1:"犬",a3:"鳥"};

配列と同様deleteを使って削除できます。

変更を禁止する

Object.freezeを使用すると連想配列の変更を禁止にできます。

constanimals=Object.freeze({a1:"",a2:"",a3:""});console.log(animals["a1"]);// 犬console.log(animals["a2"]);// 猫console.log(animals["a3"]);// 鳥animals["a4"]="";console.log(animals["a4"]);// undefinedconsole.log(animals);//{a1:"犬",a2:"猫",a3:"鳥"}

Object.freezeを使用すると配列に追加させようとしてもできていないことがわかります。

数を取得する

Object.keys(obj)を使うことでできます。

constanimals={a1:"",a2:"",a3:""};console.log(Object.keys(animals).length);// 3

Object.keysメソッドとlengthプロパティを使用して連想配列の数を取得しています。(キーと値あわせて1つと数えます。)

まとめ

少し難しいですがうまく使えると便利だと思うので少しでも役立ったら嬉しいです。

参考リンク

JavaScript 連想配列の仕組みと使い方のサンプル

Browsing Latest Articles All 31 Live