انجمن‌های فارسی اوبونتو

لطفاً به انجمن‌ها وارد شده و یا جهت ورود ثبت‌نام نمائید

لطفاً جهت ورود نام کاربری و رمز عبورتان را وارد نمائید

نویسنده موضوع: awk - مقایسه بین فیلد های دو فایل  (دفعات بازدید: 1557 بار)

0 کاربر و 1 مهمان درحال مشاهده موضوع.

آفلاین B

  • Sr. Member
  • *
  • ارسال: 354
  • جنسیت : پسر
awk - مقایسه بین فیلد های دو فایل
« : 09 بهمن 1392، 01:11 ب‌ظ »
سلام

سوالی هفته‌ی پیش توی stackoverflow پرسیده شد که از این قرار بود: (آدرس سوال)
دو فایل داریم
داخل فایل اولی دو گروه از فیلد ها رو داریم؛ مثلا:
1 2
2 3
3 6

داخل فایل دومی هم ۴ سری فیلد که فیلد‌های دوم و سوم مهم هستند؛ مثلا:
a 1 2 xx
b 2 1 xx
c 3 4 xx
d 6 3 xx


سوال از این قرار هست:
چگونه میشه خطوطی از فایل دوم رو به دست آورد که اگه فیلد دوم و سوم اون تلفیق بشن؛ یا باید به صورت مستقیم در فایل اولی وجود داشته باشه و یا برعکس اون!

مثلا در فایل اولی داشتیم
 1 2 - یعنی اگه در تلفیق ستون دوم و سوم از فایل دومی دارای عبارت 21 ویا 12 بود؛ کل اون خط از فایل دوم رو نشون بده! (باید خط اول و دوم رو نشون بده)
یا مثلا در فایل دوم؛اگر تلفبق ستون دوم و سوم؛  36 و 63 بود؛ اون خط او نشون بده! (خط آخر رو نشون میده)


در نتیجه خروجیمون باید بشه این:
a 1 2 xx
b 2 1 xx
d 6 3 xx


یه بنده‌خدایی اومد با خط کل مسله رو حل کرد:

awk 'NR == FNR {a[$1,$2]=1; a[$2,$1]=1; next} ($2 SUBSEP $3) in a' File_1 File_2


من هرچی تلاش میکنم نمیتونم متوجه بشم چه عملیاتی در حال شکل گرفت هست؛ اگه کسی متوجه میشه اینو تحلیل کنه ممنون میشم
« آخرین ویرایش: 09 بهمن 1392، 01:14 ب‌ظ توسط B »

آفلاین محسن صفری

  • Jr. Member
  • *
  • ارسال: 47
  • جنسیت : پسر
    • صفری آنلاین
پاسخ : awk - مقایسه بین فیلد های دو فایل
« پاسخ #1 : 11 بهمن 1392، 12:40 ب‌ظ »
من به این شیوه حل می کنمش که به نظرم ساده تره

awk 'NR == FNR {a[$1,$2]=1;next}a[$2,$3] || a[$3,$2]' file1 file2
NR و FNR دو تا متغیر داخلی awk هستند و a هم یک آرایه دو بعدی هست .

awk را می توانیم با چندین فایل ورودی فراخوانی کنیم و اون هم به صورت پیش فرض خط به خط فایلها رو می خونه و عملیاتش رو انجام می ده . هنگامی که کارش با یک فایل تموم شد به صورت اتوماتیک فایل دوم رو باز می کنه و همون عملیات رو تکرار می کنه. اینجا رو دقت کنید :

NR : یا number of record شماره خط هست که به به ترتیب اضافه می شه و با عوض شدن فایل ریست نمی شود.
FNR : یا File number of record به ترتیب اضافه می شه و با عوض شدن فایل یک می شه . در واقع شماره خط جاری در داخل فایل جاری هستش .

NR == FNR {a[$1,$2]=1;next}این قسمت کد می گه که اگر شماره خط کل با شماره خط فایل جاری یکسان بود (یعنی در داخل فایل اول بودیم) ستون یک و دو رو به عنوان اندیس آرایه a انتخاب کن و مقدارش رو هم یک بده . مقدارش اینجا مهم نیست و هر چیزی که به true تفسیر بشه می شه استفاده کرد . next در ادامه دستور می گه که دیگه نمی خواد دستورهای دیگه رو اجرا کنی و خط دیگه رو بخون

a[$2,$3] || a[$3,$2]این قسمت کد قطعا فقط در فایل های دوم به بعد اجرا می شوند . یعنی فایل هایی که NR != FNR . و چک می کنن که آیا مقادیر ستونها داخل آرایه هستن یا نه . اینجا از action استفاده نکردم چون default action توی awk پرینت هستش و خودش اتوماتیک خط رو print می کنه.

آفلاین B

  • Sr. Member
  • *
  • ارسال: 354
  • جنسیت : پسر
پاسخ : awk - مقایسه بین فیلد های دو فایل
« پاسخ #2 : 12 بهمن 1392، 04:06 ق‌ظ »
سلام

آقا محسن دمت گرم؛ منم روش کار کرده بودم و تونستم متوجه‌بشم چی به چی هست؛

روش شما هم جالب بود و فکر کنم سریع‌تر هم جواب میده؛

اون روشی که بالا نوشتم هم اون قسمتی که توضیح ندادید رو من توضیح میدم:

($2 SUBSEP $3) in a
SUBSEP یه متغیر از پیش تعیین شده در awk هست؛کاربردش هم اینه که
وقتی یه متغیر دو بعدی و یا بیشتر تعریف میکنیم؛ مثلا به شکل زیر:
a[1,2[awk میاد این ایندکس‌ها رو تبدیل میکنه به یک اینکس؛ و در بین اون‌ها کارکتری که در SUBSEP هست رو قرار میده!!!
برای مثال اگه در SUBSEP ما عبارت @ باشه؛ بعد از اینکه مقدار زیر رو تعریف کنیم:
a[1,2[awk اون رو در حافظه خودش با چنین ایندکسی ذخیره میکنه
a[1@2]
اما از دید کاربر این یک ارایه دو بعدی هست و ما میتونیم به همون شکل‌ای که به آرایه‌های دوبعدی دسترسی پیدا میکنیم به اون هم دسترسی داشته باشم



نکته دوم اینه
با دستور زیر میتونیم از وجود یک مقدار دز ارایه با خبر بشیم
() in arr


در این دستور (که فقط برای خطوط فایل دوم اجرا میشه)
($2 SUBSEP $3) in aگفته شده که فیلد دوم رو با استفاده از حداکننده‌ی SUBSEP به فیلد سوم بچسبون و اونو داخل آرایه a جست و جو کن
اگه جواب منفی اومد که هیچی؛ اگه مثبت اومد (یعنی اون عبارت داخل ایندکس a بود) همون دیفالت اکشن که آقا محسن فرمودند رو اجرا کن که در واقع همون پرینت خط هست!!



ولی همونطور که گفتم کدی که شما نوشتید سریع‌تر اجرا میشه؛ چون در کد اول به ازای هر یک خط کل آرایه باید مورد باز بینی قرار بگیره؛ ولی در حد شما فقط ۲ تا آرایه در هر مرحله چک میشه!

بازم تشکر
« آخرین ویرایش: 12 بهمن 1392، 04:33 ق‌ظ توسط B »

آفلاین محسن صفری

  • Jr. Member
  • *
  • ارسال: 47
  • جنسیت : پسر
    • صفری آنلاین
پاسخ : awk - مقایسه بین فیلد های دو فایل
« پاسخ #3 : 12 بهمن 1392، 10:46 ق‌ظ »
تعداد خونه های آرایه شما دو برابر تعداد خونه آرایه کد منه چون هر بار دو تا مقدار دهی دارید : a[$1,$2]=1; a[$2,$1]=1;
ولی کد من یکبار مقدار دهی می شه : a[$1,$2]=1;
در عوض توی فایل دوم من دو تا چک انجام می دم a[$2,$3] || a[$3,$2]در حالیکه شما فقط یک چک انجام می دید : ($2 SUBSEP $3) in a
از نظر سرعت اجرا حداقل توی این سطح از ورودی فکر نمی کنم زیاد فرقی داشته باشن.

بابت SUBSEP ممنون .
($2 SUBSEP $3) in aاین کد هر بار کل آرایه رو چک نمی کنه . بلکه به احتمال قوی این ساختار اندیس رو تشکیل می ده و بعد یکراست چک می کنه که آیا اندیس درون آرایه هست یا نه . البته احتمالا زمانی صرف تشکیل اندیس و چک کردن می شه ولی از اون جایی که این متغیر و این ساختار توی زبان گنجونده شدن نباید زیاد نگران بود بالاخره آقایان a و w و k کارشون رو بلد بودن دیگه !
« آخرین ویرایش: 12 بهمن 1392، 10:47 ق‌ظ توسط محسن صفری »