1

次のような列を持つファイルがあります。

Column1,Column2,Column3,Column4,Column5,Column6
1,2,3,4,5,6
1,2,3,4,5,6
1,2,3,4,5,6
1,2,3,4,5,6
1,2,3,4,5,6
1,2,3,4,5,6
Column1,Column3,Column2,Column6,Column5,Column4
1,3,2,6,5,4
1,3,2,6,5,4
1,3,2,6,5,4
Column2,Column3,Column4,Column5,Column6,Column1
2,3,4,5,6,1
2,3,4,5,6,1
2,3,4,5,6,1

列はファイルの途中でランダムに並べ替えられます。順序を知る唯一の方法は、データの直前のヘッダーの最後のセット (Column1、Column2 など) を確認することです (データも簡略化しました)。実際には、データはすべて大きな整数値であり、実際にはどの列にも入る可能性があるため、データを区別する方法はありません)

明らかに、これは BULK INSERT の使用に関してはあまり SQL Server に適していないため、SQL データベース内のテーブルの列順序と一致する一貫した順序ですべての列を配置する方法を見つける必要があります。これを行う最善の方法は何ですか?Python が使用する言語だと聞いたことがありますが、実際に使用したことはありません。任意の言語での提案/サンプル スクリプトを歓迎します。

4

3 に答える 3

3

Pythonでの解決策:

行ごとに読んでヘッダーを探します。ヘッダーを見つけたら、それを使用して (どういうわけか) 順序を把握します。itemgetter次に、要素の並べ替えの魔法を行うorder を渡します。

from operator import itemgetter
def header_parse(line,order_dict):
    header_info = line.split(',')
    indices = [None] * len(header_info)
    for i,col_name in enumerate(header_info):
        indices[order_dict[col_name]] = i
    return indices

def fix(fname,foutname):
    with open(fname) as f,open(foutname,'w') as fout:
        #Assume first line is a "header" and gives the order to use for the
        #rest of the file
        line = f.readline()
        order_dict = dict((name,i) for i,name in enumerate(line.strip().split(',')))
        reorder_magic = itemgetter(*header_parse(line.strip(),order_dict))
        for line in f:
            if line.startswith('Column'):  #somehow determine if this is a "header"
                reorder_magic = itemgetter(*header_parse(line.strip(),order_dict))
            else:
                fout.write(','.join(reorder_magic(line.strip().split(','))) + '\n')

if __name__ == '__main__':
    import sys
    fix(sys.argv[1],sys.argv[2])

これで、次のように呼び出すことができます。

python fixscript.py badfile goodfile
于 2012-10-23T19:09:58.697 に答える
2

これは、次の 2 つの手順で簡単に修正できます。

  • 新しいヘッダーの開始時にファイルを複数のファイルに分割する
  • csv dict リーダーを使用して各ファイルを読み取り、キーをソートして正しい順序で行を再出力します

これは、あなたがそれについてどのようにできるかの例です。

def is_header(line):
    return line.find('Column') >= 0

def process(lines):  
    headers = None
    for line in lines:
        line = line.strip()
        if is_header(line):
            headers = list(enumerate(line.split(",")))
            headers_map = dict(headers)
            headers.sort(key=lambda (i,v):headers_map[i])
            print ",".join([h for i,h in headers])
            continue

        values = list(enumerate(line.split(",")))
        values.sort(key=lambda (i,v):headers_map[i])
        print ",".join([v for i,v in values])

if __name__ == "__main__":
    import sys
    process(open(sys.argv[1]))

関数is_headerを変更して、実際のケースでヘッダーを正しく識別することもできます

于 2012-10-23T19:03:21.987 に答える
2

あなたは特定の問題について言及していないので、アルゴリズムの問​​題を抱えていると思います。

  1. 行ごとに、

    1. 行をフィールドに解析します。
    2. 最初のヘッダー行の場合、

      1. ヘッダーを出力します。
      2. 配置するフィールド名のマップを作成します。

        %map = map { $fields[$_] => $_ } 0..$#fields;
        
      3. 元の位置から新しい位置へのマップを作成します。

        @map = @map{ @fields };
        
    3. 1行目以外のヘッダー行であれば、

      1. 元の位置のマップを新しい位置に更新します。

        @map = @map{ @fields };
        
    4. ヘッダー行でない場合は、

      1. フィールドを並べ替えます。

        @fields[ @map ] = @fields;
        
      2. 行を出力します。

(スニペットは Perl です。)

于 2012-10-23T19:18:11.353 に答える