ハッシュテーブル(連想配列)を使うには?

本文介绍哈希表的基本概念及使用方法,包括项的添加、值的获取、列挙及检查等,并提供C#与VB.NET的示例代码。
部署运行你感兴趣的模型镜像

ハッシュテーブルとは、キー(key)と値(value)のペアを保持しているコレクションである。通常の配列がインデックス番号により各値(各要素)にアクセスできるのに比べて、ハッシュテーブルでは、インデックス番号の代わりにキーを用いて、その各値にアクセスすることができる。キーと、そのキーから連想される(対応付けられている)値のペアを保持しているため、ハッシュテーブルは「連想配列」とも呼ばれる。ハッシュテーブルの特長は、指定したキーから、それに対応した値を高速に得られることである。

 .NET Frameworkのクラス・ライブラリでは、ハッシュテーブルがHashtableクラス(System.Collections名前空間)で実装されている。本稿では、このHashtableクラスの基本的な利用方法についてまとめる。

ハッシュテーブルへの項目の追加

 ハッシュテーブルへの項目(キーと値のペア)の追加は、インデクサ(VB.NETの場合は既定のプロパティとなっているItemプロパティ)か、Addメソッドにより行う。

[C#の場合]
Hashtable ht = new Hashtable();
ht["japan"] = "日本";
ht.Add("china", "中国");

[VB.NETの場合]
Dim ht As Hashtable = New Hashtable
ht("japan") = "日本"
ht.Add("china", "中国")

 指定したキーがハッシュテーブル(この例ではht)に存在しない場合には、新しい要素として登録される。キーがすでに存在する場合には、インデクサではそのキーに対応する値が置き換えられるが、Addメソッドでは例外が発生する。

 なお、この例ではキーと値の両方に文字列を用いているが、実際にはObject型のキーと値が指定可能であるため、どのようなオブジェクトでもHashtableオブジェクトに格納できる。

 

ハッシュテーブル内の値の取得

 ハッシュテーブル内の値の取得は、上記と同様にインデクサ(VB.NETではItemプロパティ)によりキーを指定して行う(逆に、値からキーを直接取得することはできない)。いま述べたように、ハッシュテーブルは要素をObject型のオブジェクトとして保持しているため、必要なら元の型に変換しなければならない。

C#の場合]
string val = (string)ht["japan"];

[VB.NETの場合]
Dim str As String = CType(ht("japan"), String)

 指定したキーがハッシュテーブルに存在しない場合には、null(VB.NETではNothing)が返される。

すべてのキーや値の列挙

 ハッシュテーブルに格納されているすべてのキーあるいは値は、コレクションとしてKeysプロパティあるいはValuesプロパティからアクセスできる。このため、foreachステートメント(VB.NETではFor Each...Next)などを使って、すべてのキーや値を列挙することができる(記述例は下のサンプル・プログラムを参照)。

キーや値の存在チェック

 特定のキーや値がハッシュテーブルに格納されているかどうかは、ContainsKeyメソッドあるいはContainsValueメソッドを使用する。この2つのメソッドはbool型(VB.NETではBoolean型)の値(TrueかFalse)を返す(記述例は下のサンプル・プログラムを参照)。

ハッシュテーブルを使ったサンプル・プログラム

 ここまでの解説をまとめたサンプル・プログラム(C#版およびVB.NET版)を以下に示す。

// hashtable.cs

using System;
using System.Collections;

public class test {
  static void Main() {
    Hashtable ht = new Hashtable();

    // データの追加その1
    ht["japan"] = "日本";
    ht["america"] = "アメリカ";

    // データの追加その2
    ht.Add("china", "中国");
    ht.Add("india", "インド");

    // データの取得
    string val = (string)ht["japan"];
    Console.WriteLine(val); // 出力:日本

    // キー項目の列挙
    foreach (string key in ht.Keys) {
      Console.WriteLine("{0} : {1}", key, ht[key]);
    }
    // 出力例:
    // india : インド
    // japan : 日本
    // america : アメリカ
    // china : 中国

    // 値項目の列挙
    foreach (string value in ht.Values) {
      Console.WriteLine(value);
    }
    // 出力例:
    // インド
    // 日本
    // アメリカ
    // 中国

    // キーの存在チェック
    if (!ht.ContainsKey("france")) {
      ht["france"] = "フランス";
    }

    // 値の存在チェック
    Console.WriteLine(ht.ContainsValue("日本")); // 出力例:True

    // エントリ(キーと値)の列挙
    foreach (DictionaryEntry de in ht) {
      Console.WriteLine("{0} : {1}", de.Key, de.Value);
    }
    // 出力例:
    // india : インド
    // japan : 日本
    // france : フランス
    // america : アメリカ
    // china : 中国
  }
}

// コンパイル方法:csc hashtable.cs
ハッシュテーブルを使ったC#のサンプル・プログラム(hashtable.cs)
 
' hashtable.vb

Imports System
Imports System.Collections

Class HashTableSample
  Shared Sub Main()
    Dim ht As Hashtable = New Hashtable

    ' データの追加その1
    ht("japan") = "日本"
    ht("america") = "アメリカ"

    ' データの追加その2
    ht.Add("china", "中国")
    ht.Add("india", "インド")

    ' データの取得
    Dim str As String = CType(ht("japan"), String)
    Console.WriteLine(str) ' 出力:日本

    ' キー項目の列挙

    For Each key As String In ht.Keys
      Console.WriteLine("{0} : {1}", key, ht(key))
    Next
    ' 出力例:
    ' india : インド
    ' japan : 日本
    ' america : アメリカ
    ' china : 中国

    ' 値項目の列挙
    For Each val As String In ht.Values
      Console.WriteLine(val)
    Next
    ' 出力例:
    ' インド
    ' 日本
    ' アメリカ
    ' 中国

    ' キーの存在チェック

    If Not ht.ContainsKey("france") Then
      ht("france") = "フランス"
    End If

    ' 値の存在チェック
    Console.WriteLine(ht.ContainsValue("アメリカ")) ' 出力:True

    ' エントリ(キーと値)の列挙
    For Each de As DictionaryEntry In ht
      Console.WriteLine("{0} : {1}", de.Key, de.Value)
    Next
    ' 出力例:
    ' india : インド
    ' japan : 日本
    ' france : フランス
    ' america : アメリカ
    ' china : 中国
  End Sub
End Class

' コンパイル方法:vbc hashtable.vb
ハッシュテーブルを使ったVB.NETのサンプル・プログラム(hashtable.vb)

 

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

package jp.co.sej.ssc.cl.sclb1040; import com.google.crypto.tink.Aead; import com.google.crypto.tink.KmsClient; import com.google.crypto.tink.aead.AeadConfig; import com.google.crypto.tink.aead.AeadParameters; import com.google.crypto.tink.aead.KmsEnvelopeAead; import com.google.crypto.tink.aead.PredefinedAeadParameters; import com.google.crypto.tink.integration.gcpkms.GcpKmsClient; import jakarta.annotation.PostConstruct; import lombok.Getter; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.env.Environment; /* * 暗号化部品用のTink設定クラス * * Bean登録(コンストラクタ)のタイミングで、時間のかかる初期化処理行っておく。 */ @Log4j2 public final class Sclb1041 { //// キーテンプレート名 //private final String KEYTEMPLATE_NAME = "AES256_GCM"; //// キーテンプレート //@Getter //private KeyTemplate tinkKeyTemplate; private static final String ENVELOPE_ENCRYPTION_APP_YAML_SECTION_FIRST_KEK_URI = "envelope-encryption.keys.kek-uri.kek-uri-1"; @Getter //2023/12/05追加 定義済みAeadパラメータ private AeadParameters predefinedAeadParameters = PredefinedAeadParameters.AES256_GCM; /* * KMS未使用モード * true:KMS未使用モード / false:KMS使用モード(デフォルト)) */ @Value("${envelope_encryption_kms_use_disabled:false}") @Getter private boolean kmsUseDisabled; /* * サービスアカウント(SA)キーファイルパス */ @Value("${envelope_encryption_gcp_credential_filepath:}") @Getter private String gcpCredentialFilePath; @Autowired private Environment environment; /* * コンストラクタ * * @throws RuntimeException */ public Sclb1041() throws RuntimeException { try { // Tink初期化(サポートするAEADキータイプ登録) AeadConfig.register(); //// キーテンプレート //tinkKeyTemplate = KeyTemplates.get(KEYTEMPLATE_NAME); } catch (Exception e) { throw new RuntimeException( Sclb1050.SCLM4001 + " " + Sclb1050.SCLM40011 + ":initialization failure in bean registration.", e); } } /* * KEK(kek-uri-1)のGCPリソースID取得 * * @param kekUriName application.ymlで指定するKEK(kek-uri-1)の名前 * @return application.ymlで指定するKEK(kek-uri-1)のGCPリソースID * @throws IllegalStateException */ private String getPrepareKekUriPath() { return environment.getProperty(ENVELOPE_ENCRYPTION_APP_YAML_SECTION_FIRST_KEK_URI); } /* * Spring Bootアプリケーション起動後の処理 * Spring Bootアプリケーション起動時にCloud KMSへのアクセス行うことで、業務処理による初回Cloud KMSアクセス高速化する。 * ・暗号化処理に使用するKEKは、"kek-uri-1"で固定。 * ・暗号化処理に使用するデータはダミーデータとして0x00のみのバイト配列使用。 */ @PostConstruct protected void prepare() { if (!kmsUseDisabled) { // AEADプリミティブ Aead aead = null; Aead remoteAead = null; log.debug("preparing encryption started."); try { // キーセット //keysetHandle = KeysetHandle // .generateNew(KmsEnvelopeAeadKeyManager.createKeyTemplate(getPrepareKekUriPath(), // tinkKeyTemplate)); // KMSクライアント KmsClient kmsClient = new GcpKmsClient(); if (gcpCredentialFilePath.isEmpty()) { // サービスアカウントキー未使用(GCP環境で実行)(defaultCredentials()) //GcpKmsClient.register(Optional.of(getPrepareKekUriPath()), Optional.empty()); kmsClient.withDefaultCredentials(); } else { // サービスアカウントキー使用(withCredentials(gcpCredentialFilename)) //GcpKmsClient.register(Optional.of(getPrepareKekUriPath()), Optional.of // (gcpCredentialFilePath)); kmsClient.withCredentials(gcpCredentialFilePath); } // AEADプリミティブ remoteAead = kmsClient.getAead(getPrepareKekUriPath()); //aead = keysetHandle.getPrimitive(Aead.class); aead = KmsEnvelopeAead.create(getPredefinedAeadParameters(), remoteAead); } catch (Exception e) { log.debug("Tink initialization failure in preparing encryption.KEK name:kek-uri-1." + e.getMessage()); } // 暗号化(暗号化データ後続利用無し。ダミーデータとして0x00のみのバイト配列使用。) final byte[] preInitByte = {0}; try { if (aead != null) { aead.encrypt(preInitByte, null); } } catch (Exception e) { log.debug("preparing encryption failed.KEK name:kek-uri-1." + e.getMessage()); } log.debug("preparing encryption end."); } } } 42:package jp.co.sej.ssc.cl.sclb1040; import com.google.crypto.tink.Aead; import com.google.crypto.tink.KmsClient; import com.google.crypto.tink.aead.KmsEnvelopeAead; import com.google.crypto.tink.integration.gcpkms.GcpKmsClient; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; import org.springframework.util.SerializationUtils; /** * 暗号化部品のロジッククラス */ @Configuration @Component @Scope("prototype") @Log4j2 public class Sclb1042 { // 定数 private static final String ENVELOPE_ENCRYPTION_APP_YAML_SECTION_KEK_URI = "envelope-encryption.keys.kek-uri."; // AEADプリミティブ //private KeysetHandle keysetHandle = null; private Aead aead = null; private Aead remoteAead = null; // Tink設定 @Autowired private Sclb1041 tinkConfig; @Autowired private Environment environment; /* * KEKのGCPリソースID取得 * * @param kekUriName application.ymlで指定するKEKの名前 * @return application.ymlで指定するKEKのGCPリソースID * @throws IllegalStateException */ private String getkekUriPath(String kekUriName) throws IllegalStateException { return environment.getRequiredProperty( ENVELOPE_ENCRYPTION_APP_YAML_SECTION_KEK_URI + kekUriName); } /* * Tink初期化 * * KEK未使用モードの場合も、application.yml上のKEKと暗号化対象項目定義のチェックは行う。 * * @param kekUriName application.ymlで指定するKEKの名前 * @throws RuntimeException */ private void init(String kekUriName) throws RuntimeException { String kekUriPath = ""; try { kekUriPath = getkekUriPath(kekUriName); } catch (Exception e) { throw new RuntimeException(Sclb1050.SCLM4001 + " " + Sclb1050.SCLM40012 + ":initialization failure. KEK URI does not defined on application.yml. KEK name:" + kekUriName + ".", e); } // GCP接続処理と暗号鍵関連の初期化 if (!tinkConfig.isKmsUseDisabled()) { try { // キーセット //keysetHandle = KeysetHandle.generateNew( // KmsEnvelopeAeadKeyManager.createKeyTemplate(kekUriPath, tinkConfig // .getTinkKeyTemplate())); // KMSクライアント KmsClient kmsClient = new GcpKmsClient(); if (tinkConfig.getGcpCredentialFilePath().isEmpty()) { // サービスアカウントキー未使用(GCP環境で実行)(defaultCredentials()) //GcpKmsClient.register(Optional.of(kekUriPath), Optional.empty()); kmsClient.withDefaultCredentials(); } else { // サービスアカウントキー使用(withCredentials(gcpCredentialFilename)) //GcpKmsClient.register(Optional.of(kekUriPath), Optional.of(tinkConfig // .getGcpCredentialFilePath())); kmsClient.withCredentials(tinkConfig.getGcpCredentialFilePath()); } // AEADプリミティブ remoteAead = kmsClient.getAead(kekUriPath); //aead = keysetHandle.getPrimitive(Aead.class); aead = KmsEnvelopeAead.create(tinkConfig.getPredefinedAeadParameters(), remoteAead); } catch (Exception e) { throw new RuntimeException( Sclb1050.SCLM4001 + " " + Sclb1050.SCLM40013 + ":Tink initialization failure. KEK name:" + kekUriName, e); } } } /* * 暗号化(エンベロープ暗号化) * * 暗号化対象データバイト配列にシリアライズし、Tinkでエンベロープ暗号化する。 * * @param encryptTargetData 暗号化対象データ * @param kekUriName application.ymlで指定するKEKの名前 * @return 暗号化済みデータ * @throws RuntimeException */ public byte[] envelopeEncrypt(String encryptTargetData, String kekUriName) throws RuntimeException { return envelopeEncrypt((Object) encryptTargetData, kekUriName); } /* * 暗号化(エンベロープ暗号化) * * 暗号化対象データバイト配列にシリアライズし、Tinkでエンベロープ暗号化する。 * * @param encryptTargetData 暗号化対象データ * @param kekUriName application.ymlで指定するKEKの名前 * @return 暗号化済みデータ * @throws RuntimeException */ public byte[] envelopeEncrypt(Character encryptTargetData, String kekUriName) throws RuntimeException { return envelopeEncrypt((Object) encryptTargetData, kekUriName); } /* * 暗号化(エンベロープ暗号化) * * 暗号化対象データバイト配列にシリアライズし、Tinkでエンベロープ暗号化する。 * * @param encryptTargetData 暗号化対象データ * @param kekUriName application.ymlで指定するKEKの名前 * @return 暗号化済みデータ * @throws RuntimeException */ public byte[] envelopeEncrypt(Integer encryptTargetData, String kekUriName) throws RuntimeException { return envelopeEncrypt((Object) encryptTargetData, kekUriName); } /* * 暗号化(エンベロープ暗号化) * * 暗号化対象データバイト配列にシリアライズし、Tinkでエンベロープ暗号化する。 * * @param encryptTargetData 暗号化対象データ * @param kekUriName application.ymlで指定するKEKの名前 * @return 暗号化済みデータ * @throws RuntimeException */ public byte[] envelopeEncrypt(int encryptTargetData, String kekUriName) throws RuntimeException { return envelopeEncrypt((Object) encryptTargetData, kekUriName); } /* * 暗号化(エンベロープ暗号化) * * 暗号化対象データバイト配列にシリアライズし、Tinkでエンベロープ暗号化する。 * * @param encryptTargetData 暗号化対象データ * @param kekUriName application.ymlで指定するKEKの名前 * @return 暗号化済みデータ * @throws RuntimeException */ public byte[] envelopeEncrypt(java.sql.Timestamp encryptTargetData, String kekUriName) throws RuntimeException { return envelopeEncrypt((Object) encryptTargetData, kekUriName); } /* * 暗号化(エンベロープ暗号化) * * 暗号化対象データバイト配列にシリアライズし、Tinkでエンベロープ暗号化する。 * * @param encryptTargetData 暗号化対象データ * @param kekUriName application.ymlで指定するKEKの名前 * @return 暗号化済みデータ * @throws RuntimeException */ public byte[] envelopeEncrypt(java.sql.Date encryptTargetData, String kekUriName) throws RuntimeException { return envelopeEncrypt((Object) encryptTargetData, kekUriName); } /* * 暗号化(エンベロープ暗号化) * * 暗号化対象データバイト配列にシリアライズし、Tinkでエンベロープ暗号化する。 * * @param encryptTargetData 暗号化対象データ * @param kekUriName application.ymlで指定するKEKの名前 * @return 暗号化済みデータ * @throws RuntimeException */ public byte[] envelopeEncrypt(Object encryptTargetData, String kekUriName) throws RuntimeException { try { // Tink初期化 init(kekUriName); if (!tinkConfig.isKmsUseDisabled()) { // Tinkによる暗号化 byte[] afterEncryptBytes = aead.encrypt(serializeObject(encryptTargetData), null); return afterEncryptBytes; } else { // バイト配列化 byte[] seraializedBytes = serializeObject(encryptTargetData); return seraializedBytes; } } catch (Exception e) { // 暗号化処理でエラー発生 throw new RuntimeException( Sclb1050.SCLM4002 + " " + Sclb1050.SCLM40021 + ":encryption failure.", e); } } /* * 復号(エンベロープ暗号化) * * Tinkでエンベロープ暗号化された復号対象データ(バイト配列)復号し、Objectインスタンスにデシリアライズする。 * * @param decryptTargetData 復号対象データ * @param clazz 復号済みデータの想定型 * @param kekUriName application.ymlで指定するKEKの名前 * @return 復号済みデータ * @throws RuntimeException */ public <T> Object envelopeDecrypt(byte[] decryptTargetData, Class<T> clazz, String kekUriName) throws RuntimeException { // 復号 Object decTargetData = envelopeDecrypt(decryptTargetData, kekUriName); if (decTargetData.getClass() != clazz) { // 復号後オブジェクトの型が使用メソッドの想定型と不一致 throw new RuntimeException(Sclb1050.SCLM4003 + " " + Sclb1050.SCLM40034 + ":Object type does not match the expected object type of the using method.Expected: " + clazz.getName() + "/Decrypted: " + decTargetData.getClass().getName() + "."); } return decTargetData; } /* * 復号(エンベロープ暗号化) * * Tinkでエンベロープ暗号化された復号対象データ(バイト配列)復号し、Objectインスタンスにデシリアライズする。 * * @param decryptTargetData 復号対象データ * @param kekUriName application.ymlで指定するKEKの名前 * @return 復号済みデータ * @throws RuntimeException */ public Object envelopeDecrypt(byte[] decryptTargetData, String kekUriName) throws RuntimeException { Object decTargetData = null; try { // Tink初期化 init(kekUriName); if (!tinkConfig.isKmsUseDisabled()) { // Tinkによる復号 decTargetData = deserializeObject(aead.decrypt(decryptTargetData, null)); } else { // バイト配列からのデシリアライズ decTargetData = deserializeObject(decryptTargetData); } } catch (Exception e) { // 復号処理でエラー発生 throw new RuntimeException( Sclb1050.SCLM4003 + " " + Sclb1050.SCLM40031 + ":decryption failure.", e); } return decTargetData; } /* * Tinkにてエンベロープ暗号化されたデータ文字列(String)として復号する * * @param decryptTargetData 復号対象データ * @param kekUriName application.ymlで指定するKEKの名前 * @return 復号データ */ public String envelopeDecryptString(byte[] decryptTargetData, String kekUriName) { Object obj = envelopeDecrypt(decryptTargetData, String.class, kekUriName); return (String) obj; } /* * Tinkにてエンベロープ暗号化されたデータ文字(char)として復号する * * @param decryptTargetData 復号対象データ * @param kekUriName application.ymlで指定するKEKの名前 * @return 復号データ */ public char envelopeDecryptChar(byte[] decryptTargetData, String kekUriName) { Object obj = envelopeDecrypt(decryptTargetData, char.class, kekUriName); return (char) obj; } /* * Tinkにてエンベロープ暗号化されたデータ数値(Integer)として復号する * * @param decryptTargetData 復号対象データ * @param kekUriName application.ymlで指定するKEKの名前 * @return 復号データ */ public Integer envelopeDecryptInteger(byte[] decryptTargetData, String kekUriName) { Object obj = envelopeDecrypt(decryptTargetData, Integer.class, kekUriName); return (Integer) obj; } /* * Tinkにてエンベロープ暗号化されたデータ数値(int)として復号する * * @param decryptTargetData 復号対象データ * @param kekUriName application.ymlで指定するKEKの名前 * @return 復号データ */ public int envelopeDecryptInt(byte[] decryptTargetData, String kekUriName) { Object obj = envelopeDecrypt(decryptTargetData, int.class, kekUriName); return ((Integer) obj).intValue(); } /* * Tinkにてエンベロープ暗号化されたデータ日時(java.sql.Timestamp)として復号する * * @param decryptTargetData 復号対象データ * @param kekUriName application.ymlで指定するKEKの名前 * @return 復号データ */ public java.sql.Timestamp envelopeDecryptTimestamp(byte[] decryptTargetData, String kekUriName) { Object obj = envelopeDecrypt(decryptTargetData, java.sql.Timestamp.class, kekUriName); return (java.sql.Timestamp) obj; } /* * Tinkにてエンベロープ暗号化されたデータ日付(java.sql.Date)として復号する * * @param decryptTargetData 復号対象データ * @param kekUriName application.ymlで指定するKEKの名前 * @return 復号データ */ public java.sql.Date envelopeDecryptDate(byte[] decryptTargetData, String kekUriName) { Object obj = envelopeDecrypt(decryptTargetData, java.sql.Date.class, kekUriName); return (java.sql.Date) obj; } /* * 暗号化対象データのシリアライズ * * @param obj シリアライズ対象データ(Serializable) * @return シリアライズ済みデータ * @throws RuntimeException */ private byte[] serializeObject(Object obj) { if (obj instanceof Serializable) { return SerializationUtils.serialize(obj); } else { throw new RuntimeException( Sclb1050.SCLM4002 + " " + Sclb1050.SCLM40022 + ":object must Serializable."); } } /* * 復号済みデータのデシリアライズ * * @param data デシリアライズ対象データ * @throws IOException * @throws ClassNotFoundException */ private Object deserializeObject(byte[] data) throws IOException, ClassNotFoundException { try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data))) { return ois.readObject(); } } }
10-14
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值