LoginSignup
1
1

More than 5 years have passed since last update.

配列内の空白で区切られた文字列を処理する

Posted at

配列内の文字列を処理したいと思いました.文字列は空白で区切られています.ここから最頻値を出します.

今回は動物データの最頻値を出すという前提にしました.

$list = array("犬 柴犬",  "犬 ポメラニアン",  "猫",  "ライオン",  "熊 シロクマ", "猫 雑種", .......);

文字列は "動物名 種類" といったような形式です.しかし,種類が入っていないもの,曖昧なものもあります.ものによっては "鳥 カラス ハシボソガラス" と文字列内に含まれる情報量が多いものもあります.これを考慮し, この最頻値の区切り前の一つ目の動物名を出し,その動物名を取り除いてリストを再構成し,再帰的に処理していきます.

<?php

function ModeLocation($list) {

  // リストを昇順ソート
  sort($list);

  // 配列の要素を' '区切りで分割し、配列にする
  // キーは別で重複を削除して保存する
  // array_uniqueがキーを振り直さないことを利用する
  // e.g. "犬 柴犬" -> array("犬", "柴犬")
  $once = array();
  foreach ($list as $key => $value) {
    $list[$key] = explode(' ', $value);
    $once[] = $list[$key][0];
  }
  $once = array_unique($once);

  // 同じデータのキーを保存しておく
  $same_data_key = array();
  foreach ($once as $once_key => $once_value) {
    $same_data_key[] = $once_key;
  }

  // キーを保存したので,キーを振りなおす
  // (カウント関数のキーと対応を取るため)
  $once = array_values($once);

  // 最頻値を求めるためのカウント処理
  // 正規表現を使って "犬" といったキーワードのものを探す
  // list配列の1つ目の要素に文字列ないの上位のものがくるので,それをカウントする
  // e.g. array("犬", "柴犬")とあったら,"犬"が上位となる
  $data_count = array_fill(0, count($once), 0);
  foreach ($once as $once_key => $once_value) {
    foreach ($list as $list_key => $list_value) {
      if (isset($list_value[0]) && preg_match("/".$once_value."/u", $list_value[0])) {
        $data_count[$once_key]++;
        array_shift($list[$list_key]);
      }
    }
  }

  // 最頻値を出す.
  // max関数ではキーを取り出せないので,降順ソートして先頭のキーを取り出す
  arsort($data_count);
  $max_loc = $once[reset(array_keys($data_count))];

  // 再帰をするための前処理
  // listはソートされており,同じ上位の単語のものが並んでいる
  // same_data_keyにはそのキーが保存されている
  // 同じ上位の単語のキーを取り出す
  // start_key ~ end_key までが同じ上位の単語となる
  $start_key = $same_data_key[array_search($max_loc, $once)];
  $end_key = $same_data_key[array_search($start_key, $same_data_key)+1];

  // 次のリストを作成する
  // 再帰的に処理を行うので,引数の形式を揃えておく
  // 配列が空のものは除いておく
  $next_list = array();
  for ($i = $start_key; $i < $end_key-1; $i++) {
    if (!empty($list[$i])) {
      $next_list[] = implode(' ', $list[$i]);
    }
  }


  // 配列が空の場合は,再帰処理を行わずに現在の最頻値の値を返す
  if (!empty($next_list)) {
    return $max_loc . " " . ModeLocation($next_list);
  } else {
    return $max_loc;
  }
}
?>

自分のプロジェクトに合わせて作ったので,下位の用語がないものでも他の下位のものがあれば調べるようになっています.例えば,"猫"と"猫 雑種"などの要素があり,データ量が "猫" > "猫 雑種" でも回答は"猫 雑種"となってしまいます.やりたいことは単純なのですが,オーバーヘッドが大きいので,どうにか改良したいですね.

1
1
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1