none
同一ファイル内における、部分的重複のある行の処理について RRS feed

  • 質問

  • import-csvでCSVファイルを読み込んだオブジェクト $LIST があるとします。

    -------CSVファイル中身----------------
    timestamp,eventid,logonid
    2015/03/12 13:24:01,4444,10000001
    2015/03/13 13:24:02,4444,10000002
    2015/03/14 13:24:03,4444,10000003
    2015/03/15 13:24:04,5555,10000001
    2015/03/16 13:24:05,5555,19999999
    2015/03/17 13:24:06,5555,10000003
    -------------------------------------


    「$LISTを1行ずつ読み取り、その行の第3フィールドの値が後続の行の同じフィールドにあるかどうか」
    を判定したいと思います。

    たとえば先頭の行の第3フィールドの値"10000001"と、別の行の第3フィールドの値とが一致していた場合、
    比較元(先頭の行)にフィールドを追加し、比較先の行の第1フィールドの値を挿入することを考えております。


    -------期待する出力----------------
    timestamp,eventid,logonid,destination
    2015/01/12 11:21:01,4444,10000001,2015/04/15 14:24:04
    2015/02/13 12:22:02,4444,10000002,NotMatch!!
    2015/03/14 13:23:03,4444,10000003,2015/06/17 16:21:06
    2015/04/15 14:24:04,5555,10000001,2015/01/12 11:21:01
    2015/05/16 15:25:05,5555,19999999,NotMatch!!
    2015/06/17 16:21:06,5555,10000003,2015/03/14 13:23:03

    $LIST | group-object logonid
    で、特定フィールドにおいて重複する行が存在するかどうか自体を確認することはできたのですが、
    ここから突破口は無いものでしょうか。

    テキストファイル化して、ファイルを読み込んで1行ごとにファイルを再度読み込み・・・・という処理に頼らずにです。

    よろしくおねがいいたします。
    2015年3月12日 7:43

回答

  • こういう感じでしょうか?

    ファイルの再読み込みこそしていないものの、オンメモリで二重ループしているので、レコード数が多い場合は遅くなると思います。

    $list | select timestamp, eventid, logonid, @{
        Name = "destination"
        Expression = {
            $ref = $_
            $dif = $list | where {$_.eventid -ne $ref.eventid -and $_.logonid -eq $ref.logonid}
            if($null -eq $dif)
            {
                "NotMatch!!"
            }
            else
            {
                $dif.timestamp
            }
        }
    }

    logonidが重複する場合は必ず2個で、それ以外は必ず1個という条件を加味してもうちょっとちゃんとアルゴリズムを考えれば、速度は改善できると思います。が、とりあえずはこれでどうでしょうか。

    • 回答としてマーク Fuzitaman 2015年3月13日 9:52
    2015年3月12日 11:49
    モデレータ

すべての返信

  • CSVファイル中身と期待する出力との内容があまりにかけ離れていてサンプルの意味を成していません。

    > で、特定フィールドにおいて重複する行が存在するかどうか自体を確認すること
    を記載いただけたらそこから話が進むと思います。

    2015年3月12日 9:02
  • こういう感じでしょうか?

    ファイルの再読み込みこそしていないものの、オンメモリで二重ループしているので、レコード数が多い場合は遅くなると思います。

    $list | select timestamp, eventid, logonid, @{
        Name = "destination"
        Expression = {
            $ref = $_
            $dif = $list | where {$_.eventid -ne $ref.eventid -and $_.logonid -eq $ref.logonid}
            if($null -eq $dif)
            {
                "NotMatch!!"
            }
            else
            {
                $dif.timestamp
            }
        }
    }

    logonidが重複する場合は必ず2個で、それ以外は必ず1個という条件を加味してもうちょっとちゃんとアルゴリズムを考えれば、速度は改善できると思います。が、とりあえずはこれでどうでしょうか。

    • 回答としてマーク Fuzitaman 2015年3月13日 9:52
    2015年3月12日 11:49
    モデレータ
  • こんばんは、

    ログオンイベントとログオフイベントをユーザーごとに1行で表示するような事をやりたいのでしょうか。

    以前、PCの起動・終了イベントを拾って1行で表示するスクリプトを作ったことがあります。
    ロジック的には同じ様な気がしますので、もしご参考になれば。

    http://mtgpowershell.blogspot.jp/2012/05/pc.html

    2015年3月12日 15:13
  • それだと

    2015/03/12 13:24:01,4444,10000001,2015/03/15 13:24:04
    2015/03/15 13:24:04,5555,10000001,2015/03/12 13:24:01
    2015/03/19 13:24:09,6666,10000001,2015/03/12 13:24:01

    のように初回行は2回目行の、それ以外は初回行の値になってしまいますよね? ですが質問文には

    「$LISTを1行ずつ読み取り、その行の第3フィールドの値が後続の行の同じフィールドにあるかどうか」

    とあり条件を満たせていないようにも思います。ですので正しいサンプルが重要と考えました。

    2015年3月13日 1:27
  • 今、自分が明示した条件がおかしいことを理解しました。

    「後続の行」という条件では、確かに期待する出力はあり得ないと思います。

    正しくは、

    「$LISTを1行ずつ読み取り、その行の第3フィールドの値が、"別の行"の同じフィールドにあるかどうか」

    となります。申し訳ありません。

    2015年3月13日 2:38
  • ありがとうございます、おかげさまで解決いたしました。

    2015年3月13日 9:54
  • 普段お世話になっているサイトですが、これは知りませんでした。ありがとうございます!

    確かに、1行でペアを表示させたい気になってきました。ちょっと取り組んでみます。ありがとうございました。

    2015年3月13日 9:57