プログラム 技術

重複した行をデータ内から除外する

今回は以前紹介した差分取得と似た内容となりますが、重複した内容のものを削除する方法となります

名称バージョン
Python3.12
PowerShell7.5.4
関連記事
C#でCSVファイルからDiffを取る - ナストンのまとめ
C#でCSVファイルからDiffを取る - ナストンのまとめ

前回はPowerShellでCSVファイルに対するDiffを出力しましたが今回はC#でのDiffの出力の仕方となります ...

関連記事へ

関連記事
PowerShellでCSVファイルからDiffを取る - ナストンのまとめ
PowerShellでCSVファイルからDiffを取る - ナストンのまとめ

同じ列内容で構成されている2つのCSVファイルからDiff(差分)をプログラムで取る必要があったので、その時のメモとなり ...

関連記事へ

Pythonの場合

特に追加のパッケージを使用することなく実装できるものとなっています

from pathlib import Path      # ファイルパス操作を簡潔にする
import shutil                # ファイル移動(上書き)に使用
import tempfile              # 一時ファイル作成に使用
import os                     # os 関連のユーティリティ

def dedupe_stream(infile, inplace=False, ignore_case=False, trim=False, encoding="utf-8"):
    # 呼び出し時の引数を表示
    print(
        f"dedupe_stream called with infile={infile!r}, inplace={inplace}, "
        f"ignore_case={ignore_case}, trim={trim}, encoding={encoding!r}"
    )

    # 入力ファイルの Path オブジェクト化
    p = Path(infile)

    # 一時ファイルを作成する
    # mkstemp は (fd, path) を返すため [1] でパスのみ取得して Path 化
    fd, tmp_path = tempfile.mkstemp(prefix=p.name + ".", suffix=".tmp")
    os.close(fd)  # <-- ここで mkstemp が返した fd を閉じる(Windows対策)
    outpath = Path(tmp_path)

    # 既出キーを記録する集合(メモリ使用量はユニーク行数に依存)
    seen = set()

    # 行から重複判定用のキーを作る内部関数
    def key(line):
        # 改行と CR を除去してベースキーを作る
        k = line.rstrip("\r\n")
        # trim=True の場合は**末尾の空白またはタブ**を除去する(先頭は残す)
        if trim:
            k = k.rstrip(" \t")
        # ignore_case オプションが有効なら小文字化(ASCII/Unicode に依存)
        if ignore_case:
            k = k.lower()
        return k

    # 入出力をテキストモードで開く(エンコーディングを指定)
    # 大きいファイルを想定しているため一行ずつストリーム処理する
    with p.open("r", encoding=encoding) as r, outpath.open("w", encoding=encoding) as w:
        for line in r:
            # 各行からキーを生成
            k = key(line)
            # まだ見ていないキーなら出力し、seen に追加(順序を保持)
            if k not in seen:
                seen.add(k)
                w.write(line)
            # 既に見たキーなら何もしない(重複行をスキップ)

    # inplace フラグが立っていれば一時ファイルで元ファイルを置き換える
    if inplace:
        # shutil.move は既存ファイルを上書きする
        shutil.move(str(outpath), str(p))
    else:
        # 置換しない場合は生成した一時ファイルのパスを出力する
        print(f"written to {outpath}")

PowerShellの場合

こちらもPython同様に追加のモジュールを使用することなく実装できるものとなっています

function Invoke-DedupeStream {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$InFile,
        [switch]$InPlace,
        [switch]$IgnoreCase,
        [switch]$Trim,
        [string]$Encoding = 'utf-8'
    )

    Write-Host (
        "Invoke-DedupeStream called with InFile='{0}', InPlace={1}, IgnoreCase={2}, Trim={3}, Encoding='{4}'" -f $InFile, $InPlace.IsPresent, $IgnoreCase.IsPresent, $Trim.IsPresent, $Encoding
    )

    $path = [System.IO.Path]::GetFullPath($InFile)
    if (-not (Test-Path -LiteralPath $path -PathType Leaf)) {
        throw "Input file not found: $path"
    }

    # 一時ファイルのパスを同じディレクトリ内に構築する
    $tempName = ([System.IO.Path]::GetFileName($path)) + '.' + [System.IO.Path]::GetRandomFileName() + '.tmp'
    $tempPath = [System.IO.Path]::Combine([System.IO.Path]::GetDirectoryName($path), $tempName)

    try {
        $enc = [System.Text.Encoding]::GetEncoding($Encoding)
    } catch {
        throw "Unsupported encoding: $Encoding"
    }

    # 既に見たキー用のハッシュセット(順序比較を使用、-IgnoreCaseの場合は手動で小文字化)
    $seen = New-Object System.Collections.Generic.HashSet[string] ([System.StringComparer]::Ordinal)

    $fsIn = [System.IO.File]::OpenRead($path)
    $sr = New-Object System.IO.StreamReader($fsIn, $enc, $true)

    $fsOut = [System.IO.File]::Open($tempPath, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write, [System.IO.FileShare]::None)
    $sw = New-Object System.IO.StreamWriter($fsOut, $enc)

    try {
        while (($line = $sr.ReadLine()) -ne $null) {
            $k = $line
            if ($Trim) { $k = $k -replace '[ \t]+$', '' }
            if ($IgnoreCase) { $k = $k.ToLowerInvariant() }
            if (-not $seen.Contains($k)) {
                $seen.Add($k) | Out-Null
                # 元の行を書き出す
                $sw.WriteLine($line)
            }
        }
    }
    finally {
        $sr.Dispose()
        $sw.Dispose()
    }

    if ($InPlace) {
        Move-Item -LiteralPath $tempPath -Destination $path -Force
    } else {
        Write-Host "written to $tempPath"
        return $tempPath
    }
}

今回重複する行を削除するというPythonとPowerShellの内容のものを紹介しましたが追加パッケージ等なくまた、実装方法もそこまで複雑ではないため紹介した2言語以外でも実装はできると思います

会社紹介

私が所属しているアドバンスド・ソリューション株式会社(以下、ADS)は一緒に働く仲間を募集しています

会社概要
「技術」×「知恵」=顧客課題の解決・新しい価値の創造

この方程式の実現はADSが大切にしている考えで、技術を磨き続けるgeekさと、顧客を思うloveがあってこそ実現できる世界観だと思っています
この『love & geek』の精神さえあれば、得意不得意はno problem!
技術はピカイチだけど顧客折衝はちょっと苦手。OKです。技術はまだ未熟だけど顧客と知恵を出し合って要件定義するのは大好き。OKです
凸凹な社員の集まり、色んなカラーや柄の個性が集まっているからこそ、常に新しいソリューションが生まれています

ミッション
私たちは、テクノロジーを活用し、業務や事業の生産性向上と企業進化を支援します

ホームページ
アドバンスド・ソリューション株式会社|ADS Co., Ltd.
アドバンスド・ソリューション株式会社|ADS Co., Ltd.

Microsoft 365/SharePoint/Power Platform/Azure による DX コンサル・シス ...

サイトへ移動

PR

-プログラム, 技術
-,