2014/05/02
今日のワンライナー その1:配列から最も要素数の多い要素を取りだす
また続くかどうか不明の新シリーズ。今日書いたワンライナーを記録していきます。
今回は、配列に含まれる要素のうち、もっとも出現頻度の多いものを調べる方法です。たとえば、0, 0, 0, 1, 0, 3, 0, 2, 0, 2という配列がある場合、「0」は6個含まれており最も要素数が多いので、この場合「0」を出力します。
ワンライナーは以下のようになります。(配列変数の宣言を合わせると2ラインですけど)
$array = 0, 0, 0, 1, 0, 3, 0, 2, 0, 2 $array | group | sort Count -Descending | select -First 1 | select -Expand Name
今回のケースのように、「配列内に同一の要素が含まれており、要素ごとに纏める」という手順が必要なときはGroup-Objectコマンドレット(エイリアス:group)の出番です。
$array | group とすると、
Count Name Group ----- ---- ----- 6 0 {0, 0, 0, 0...} 1 1 {1} 1 3 {3} 2 2 {2, 2}
のような出力が得られます。Count=出現回数、Name=要素、Group=該当する要素のリスト です。なのでこの出力だけでお題の解答である「0」が確認できます。あとはこの出力から求める値を抽出するだけです。
Group-Objectコマンドレットの出力はGroupInfoというオブジェクトです。そう、これもオブジェクトなので、他のオブジェクト同様、プロパティ情報を保ったまま後続パイプラインに渡すことができます。
まずSort-Objectコマンドレット(エイリアス:sort)を用いてGroupInfoのCountプロパティの値で降順ソート(-Descendingパラメータ使用)をかけます。するとCountプロパティが一番大きいGroupInfoオブジェクトが一番最初の要素となります。(今回の場合はたまたまソート前後で最初の要素が同じでしたが)
次にSelect-Objectコマンドレット(エイリアス:select)に-First 1と指定することで一番最初のGroupInfoオブジェクトのみ取得します。最後に、GroupInfoオブジェクトのNameプロパティの値だけを取りだすのにSelect-Objectコマンドレットに -ExpandPropertyパラメータを指定します。
ところでGroupInfoオブジェクトのGroupプロパティ、どうせNameと同じものがCount分列挙されるだけじゃないか何の意味が?と思われるかも知れないので補足です。Group-Objectコマンドレットには-Propertyパラメータ(位置パラメータなのでパラメータ名は省略可能)が定義されており、指定すると任意のプロパティ値に基づいてグループ化してくれます。
たとえば
dir | group Extension
とすると、カレントディレクトリに含まれるファイルが拡張子別にグループ化され、以下のような出力が得られます。
Count Name Group ----- ---- ----- 1 .gadget {twitterpost.gadget} 59 .vbs {7zip_fix_archive.vbs, 7zip_store_each.vbs...} 72 .ps1 {cddrive.ps1, clipboard.ps1, cmdlets.ps1...}
このようにGroupプロパティの中身は、指定プロパティ値を持つ要素のグループとなっていることが分かると思います。
-Propertyパラメータには集計プロパティを指定することもできるので、
1..10 | group {if($_ % 2 -eq 0){"偶数"}else{"奇数"}}
Count Name Group ----- ---- ----- 5 奇数 {1, 3, 5, 7...} 5 偶数 {2, 4, 6, 8...}
みたいなこともできたりします。
ちなみにGroup情報が不要であるときは、Group-Objectコマンドレットに -NoElementパラメータを付与すると出力を抑制できます。(この場合、出力はGroupInfoオブジェクトではなく、GroupInfoNoElementオブジェクトとなる)
なんか後半はGroup-Objectコマンドレット特集みたくなってしまいました。ではまた次回。
プライバシーポリシー