質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Q&A

解決済

2回答

284閲覧

複数のデータからキーが一致したデータを削除して次に渡す方法

dousuruyo

総合スコア74

bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

0グッド

1クリップ

投稿2017/10/18 02:21

編集2017/10/18 04:22

###前提・実現したいこと
BASHです
ただ、ロジック、というかアルゴリズム、というか考え方自体を知りたいです!
最初のデータを示すと、以下のことを実現したいと思ってます

in
aa bb date no cd price qty
test 2101813 20170906 001602 2132650430401 0.00 1
test 2101813 20170906 001602 2132650430401 0.00 1
test 2101813 20170906 001602 2132650430401 0.00 1

test 2101813 20170906 001603 2132650430401 0.00 1
test 2101813 20170906 001603 2132650430409 0.00 1
test 2101813 20170906 001603 2132650431301 0.00 1

test 2101813 20170906 001604 2132650430401 0.00 -1
test 2101813 20170906 001604 2132650430401 0.00 -1

out
aa bb date no cd price qty
test 2101813 20170906 001602 2132650430401 0.00 1

test 2101813 20170906 001603 2132650430401 0.00 1
test 2101813 20170906 001603 2132650430409 0.00 1
test 2101813 20170906 001603 2132650431301 0.00 1

aa,bb,date,cdをキーとして、(price*qty)がちょうどマイナスとプラスで絶対値が一致するデータを相殺して表示しないようにしたいです
なお、キーが一致するレコードは複数存在しうります

マイナスデータはあぶれたぶんはそのまま次の処理に渡すイメージ、
プラスデータも同様
マイナスデータに対応した個数分プラスデータもあわせて削除するイメージです
マイナスやプラスデータはどの場所にあってもおかしくないです
マイナスデータ及びそれに対応したプラスデータは一種類とは限りません


コードはすいませんが、現場独自のコマンドを多用している状態なので、ここでは載せられません

この部分のロジックをどうやって実現するかで、詰まっています
見づらいと思いますが、すいませんがロジックや考え方を教えていただけるとありがたいです

###現状困っている点
現状は、マイナスデータを最初にすべて抽出して、それを回したwhileループ中で、
マイナスデータとキーがすべて一致する、かつ、price*qtyの絶対値が一致する
というデータの行数を一行取得して、その後awk中のexitで次のwhileループに入る、という形をとっています

ただ、これだとキーが重複するレコードがマイナス、プラスともに複数あった場合に、プラスのほうのデータを一つしか相殺することができないので困ってます・・

while 必要なカラム(qtyがマイナスであるレコードの各カラム) ; do cat 元データ | awk ' if(キー値がすべてwhileループで回っているそれと一致すること){ prc=((%price*%qty)) prc_minus=(("'"$price"'"*"'"$qty"'"*-1)) if(prc==prc_minus){print NR" t";print "'"$nr"'"" t";exit;} ##ここでexitすることで次のwhileループへ行く } ' done > 行数と削除フラグを持った中間ファイル

イメージ上記のように組んでいる現状です。。

###補足情報(言語/FW/ツール等のバージョンなど)
bashで使ってます!

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

showkit

2017/10/18 03:13

bash とおっしゃっているのは、シェルスクリプトを組みたいということですか?
dousuruyo

2017/10/18 04:02

はい、shellscropt上で上記のデータ加工をしたい場合のロジックを知りたい、というとこです
guest

回答2

0

ベストアンサー

ご質問の出力例は間違っている気がします。(price*qty)の値がちょうどマイナスと書かれてますが、例にあるpriceは全部0.00なので乗算した結果は全部0ですよね・・・

そのため、次のように仮定したコードを書いてみました。

  • (price*qty)ではなくqtyの値だけに着目
  • 最初に出現した一致データを削除対象にする
  • 先頭行はそのまま出力
  • 7フィールドでない行は無視

filter.awk

NR == 1 { print ; next } NR != 1 && NF == 7 { aa=$1 bb=$2 date=$3 cd=$5 price=$6 qty=$7 k=aa","bb","date","cd v1=qty v2=-v1 if (!head[k,v2]) { append(k,v1,NR) a[NR]=$0 } else { dropHead(k,v2) } } END { for(r in a) if (a[r]) print a[r] } function append(k,v,r) { if (!head[k,v]) { head[k,v]=tail[k,v]=r } else { cdr[tail[k,v]]=r tail[k,v]=r } } function dropHead(k,v ,h) { h=head[k,v] if (h==tail[k,v]) { head[k,v]=tail[k,v]=0 } else { delete a[h] head[k,v]=cdr[h] } }

bash

1$ awk -f filter.awk < in 2aa bb date no cd price qty 3test 2101813 20170906 001602 2132650430401 0.00 1 4test 2101813 20170906 001603 2132650430401 0.00 1 5test 2101813 20170906 001603 2132650430409 0.00 1 6test 2101813 20170906 001603 2132650431301 0.00 1

もしprice*qtyの値の正負の一致で処理したいのなら、上のawkスクリプトのv1への代入の右辺を変えればよいと思います。

最後に自分のは素朴な感じの実装ですし充分注意深くコーディングできているかどうか保証の限りではないです。またもっとスッキリと実現できる方がいらっしゃる気がします。

投稿2017/10/18 04:39

KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dousuruyo

2017/10/18 05:00

サンプルまで貼り付けてくださって、回答ありがとうございます! すいませんが、どういったロジックの処理を行っているのか、簡単に説明していただけないでしょうか?>< ちょっと処理が難しすぎてすぐにはわからない・・ 早速、できる形で組み込んでみて動きを見させてもらいます!
KSwordOfHaste

2017/10/18 05:41 編集

awkの配列は連想配列であることはご存知と思います。本回答は特定のaa,bb,date,cd,qtyについて該当する行番号(NR)のリストを覚えておく(以下の3つの配列変数によって)という考え方です。 head[aa,bb,date,cd,qty]はリストの先頭の行番号 head[aa,bb,date,cd,qty]はリストの末尾の行番号 cdr[r]はr行目と同じaa,bb,date,cd,qtyとなるような次のレコード番号 行の内容自体はa[行番号]に覚えてます。appendで要素(行番号)を末尾に追加、dropHeadで先頭要素を削除するとともに削除する要素にあたる行の内容をaからdeleteするという感じです。
dousuruyo

2017/10/18 05:57

丁寧にご説明ありがとうございます! 結局、自分のbashの中にawkの部分を組み込んで流してみたのですが、ヘッダーカラムしか取り出せず、原因も詳しくは追えませんでした。。 ただ、確認したところキーの一つ、「cd」が一意だったようで勘違いしていたので、キーが一意なら今までのロジックで実現できそう…ということになりました。。 色々とありがとうございました!
guest

0

bashで作成してみました 値を変えています。

bash

1#!/bin/sh 2ar=() 3br=() 4IFS_BK=$IFS 5IFS=$'\n' 6while read dt 7do 8 if [ ${dt##* } -ge 0 ]; then 9 ar+=($dt) 10 else 11 br+=($dt) 12 fi 13done<<EOF 14test 2101813 20170906 001602 2132650430401 5.00 2 15test 2101813 20170906 001602 2132650430401 5.00 3 16test 2101813 20170906 001602 2132650430401 5.00 4 17test 2101813 20170906 001603 2132650430401 5.00 5 18test 2101813 20170906 001603 2132650430409 6.00 6 19test 2101813 20170906 001603 2132650431301 8.00 7 20test 2101813 20170906 001604 2132650430401 5.00 -2 21test 2101813 20170906 001604 2132650430401 5.00 -3 22EOF 23 24for aw in ${ar[@]} 25do 26 ak=$(echo $aw |cut -d\ -f1,2,3,5) 27 an=$(echo $aw |cut -d\ -f6,7|sed "s/ / * /"|bc) 28 for bw in ${br[@]} 29 do 30 bk=$(echo $bw |cut -d\ -f1,2,3,5) 31 bn=$(echo $bw |cut -d\ -f6,7|sed -e"s/ / * /" -e"s/$/ * -1/"|bc) 32 if [ "$ak" == "$bk" -a $(echo "$an == $bn"|bc) -eq 1 ]; then 33 continue 2 34 fi 35 done 36 echo $aw 37done 38 39for bw in ${br[@]} 40do 41 bk=$(echo $bw |cut -d\ -f1,2,3,5) 42 bn=$(echo $bw |cut -d\ -f6,7|sed -e"s/ / * /" -e"s/$/ * -1/"|bc) 43 for aw in ${ar[@]} 44 do 45 ak=$(echo $aw |cut -d\ -f1,2,3,5) 46 an=$(echo $aw |cut -d\ -f6,7|sed "s/ / * /"|bc) 47 if [ "$ak" == "$bk" -a $(echo "$an == $bn"|bc) -eq 1 ]; then 48 continue 2 49 fi 50 done 51 echo $bw 52done

投稿2017/10/18 07:15

編集2017/10/18 07:24
A.Ichi

総合スコア4070

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dousuruyo

2017/10/20 07:34

遅くなってすいません、回答ありがとうございます! 今回はまた仕様が変わったのでせっかくソースを書いていただいたところすいませんが、直接はそのソースをこちらで使っているものに組み込むことはできませんが、 現在の仕様のほうに応用して組み込んでみます ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問