ট্র্যাক
/
jq
jq
/
অনুশীলনী
/
শপিং লিস্ট
শপিং লিস্ট

শপিং লিস্ট

লার্নিং অনুশীলনী

ভূমিকা

মূল বিষয়গুলো

আমরা ধরে নিচ্ছি আপনি JSON সিনট্যাক্স ও ডেটা টাইপের সাথে পরিচিত।

jq আগত JSON ডেটাকে একটি একক এক্সপ্রেশন-এর (যা ফিল্টারগুলোর একটি পাইপলাইনে লেখা) মধ্য দিয়ে পাঠিয়ে কাঙ্ক্ষিত রূপান্তরিত ডেটা তৈরি করে।

Note

jq ভাষাটি jq প্রোগ্রাম দিয়ে বাস্তবায়িত হয়েছে। এই প্রোগ্রামটি বেশ কিছু সুবিধাজনক কমান্ড-লাইন অপশন দেয়, যেগুলো দিয়ে ইনপুট কীভাবে পড়া হবে আর আউটপুট কীভাবে দেখানো হবে তা নিয়ন্ত্রণ করা যায়।

নিচের উদাহরণগুলোতে আপনি পাবেন:

  • -n অথবা --null-input

    সাধারণত jq প্রোগ্রামকে পড়ার জন্য একটি ফাইল দেওয়া হয়, অথবা আপনি তার ইনপুটে ডেটা পাঠান। --null-input অপশনটি দিয়ে কোনো ইনপুট ছাড়াই JSON ডেটা তৈরি করা যায়।

  • -c অথবা --compact-output

    jq ডিফল্টভাবে তার আউটপুট সুন্দরভাবে সাজিয়ে দেখায়। ডেটা সুন্দরভাবে সাজানো থাকলে মানুষ তার দিকে তাকাতে দারুণ সুবিধা পায়। কিন্তু মেশিনের জন্য তা দরকার নেই: --compact-output অপশনটি ফরম্যাটিংয়ের হোয়াইটস্পেস সরিয়ে দিয়ে ফলাফল JSON-এর আকার কমিয়ে আনে।

  • -f filename অথবা --from-file filename

    কমান্ড লাইনে jq প্রোগ্রামটি না দিয়ে বরং filename থেকে তা পড়ুন। sed আর awk দুটোই একই উদ্দেশ্যে -f অপশন ব্যবহার করে। প্র্যাকটিস অনুশীলনীগুলোর টেস্ট স্ক্রিপ্টে এটি ব্যবহৃত হতে দেখবেন।

এই পাঠের বাকি অংশে আমরা jq ভাষা নিয়েই আলোচনা করব।

ফিল্টার ও পাইপ

ফিল্টারকে এক্সপ্রেশনও বলা হয়।

একটি ফিল্টার একটি ইনপুট নেয় আর একটি আউটপুট তৈরি করে। ইউনিক্স শেল-এ যেভাবে কাজ করেন, ঠিক সেভাবেই আপনি পাইপ | দিয়ে _ফিল্টার_গুলো জুড়ে দিতে পারেন, যাতে এক ফিল্টারের আউটপুট আরেকটির ইনপুটে যুক্ত হয়।

আইডেন্টিটি ফিল্টার: .

এটি সবচেয়ে সহজ ফিল্টার। এটি কেবল তার ইনপুটকে আউটপুটে পাঠিয়ে দেয়।

$ echo '[1, 2, 3]' | jq '.'
[
  1,
  2,
  3
]

অ্যারে

এটি অ্যারে নিয়ে কাজ করার একটি সংক্ষিপ্ত পরিচিতি হবে। এই বিষয়ে বিস্তারিত আলোচনা পরে করব।

অ্যারে-র এলিমেন্ট অ্যাক্সেস করা হয় বন্ধনী দিয়ে, আর ইনডেক্স শুরু হয় শূন্য থেকে।

$ echo '[10, 20, 30]' | jq '.[1]'
20

একটি ফিল্টার একটি এক্সপ্রেশনকে [ আর ] দিয়ে মুড়ে অ্যারে তৈরি করতে পারে

  • এলিমেন্টের একটি জানা তালিকা দিয়ে:

    jq -n '[1, 2, 3]'
    
  • এলিমেন্টের একটি স্ট্রিম সংগ্রহ করতে: যেমন, range একটি ফাংশন, যা সংখ্যার একটি স্ট্রিম আউটপুট দেয়

    $ jq -n 'range(10; 70; 15)'
    10
    25
    40
    55
    

    [] ব্যবহার করলে এক্সপ্রেশনের ফলাফলগুলো একটি অ্যারেতে জমা হয়

    $ jq -c -n '[range(10; 70; 15)]'
    [10,25,40,55]
    

কমা একটি অপারেটর

কমা কেবল অ্যারে-র এলিমেন্ট আলাদা করার সিনট্যাক্স নয়। কমা একটি অপারেটর, যা স্ট্রিমগুলো জুড়ে দেয়।

যেমন [1, 2, 3] হলো একটি ফিল্টার, যা [] অ্যারে কনস্ট্রাক্টর দিয়ে 1, 2 আর 3 এই তিনটি এক্সপ্রেশন জোড়া লাগানোর ফল একত্র করে।

উপরের range(10; 70; 15)-এ সেমিকোলনগুলো খেয়াল করেছেন? jq ভাষায় কমা-র একটি নির্দিষ্ট কাজ থাকায়, একাধিক আর্গুমেন্ট নেওয়া ফাংশনগুলো আর্গুমেন্ট আলাদা করতে সেমিকোলন ব্যবহার করে।

অবজেক্ট

অবজেক্ট নিয়ে একটি সংক্ষিপ্ত পরিচিতি।

অনেক প্রোগ্রামিং ভাষার মতোই, অবজেক্ট-এর প্রপার্টি অ্যাক্সেস করতে ডট ব্যবহার করুন

$ echo '{"foo": {"bar": "qux"}}' | jq '.foo.bar'
"qux"
Note

বন্ধনী অবজেক্ট-এর জন্যও ব্যবহার করা যায়, তবে তখন স্ট্রিং লিটারালের জন্য কোটেশন লাগবে। স্পেস থাকা কী (key) নিয়ে কাজ করার এটি একটি উপায়।

$ echo '{"foo bar": "qux"}' | jq '.["foo bar"]'
"qux"

{} আর key: value জোড়া দিয়ে আপনি একটি অবজেক্ট তৈরি করতে পারেন। কী (key) যদি "সহজ" স্ট্রিং হয়, তবে তার চারপাশে কোটেশন লাগে না।

jq -n '{question: (6 * 9), answer: 42}'

এর আউটপুট

{
  "question": 54,
  "answer": 42
}

কী (key)-কে একটি এক্সপ্রেশন হিসেবে ধরতে হলে, এটিকে প্রথম বন্ধনী দিয়ে মুড়তে হবে (নিচেরটিও উপরের মতোই আউটপুট দেয়)।

echo '[{"key":"question", "value":54}, {"key":"answer", "value":42}]' \
| jq '{(.[0].key): .[0].value, (.[1].key): .[1].value}'

পাইপলাইন

যেমন, file.json-এ আছে

{
  "key1": "value1",
  "key2": [5, 15, 25]
}

চলুন key2 অ্যারে-র দৈর্ঘ্য বের করি:

$ jq '.key2 | length' file.json
3

আমরা .key2 এক্সপ্রেশনের আউটপুটকে length-এর ইনপুট হিসেবে পাইপ করছি, আর এটি অ্যারে-র এলিমেন্টের সংখ্যা আউটপুট দেয়, তাতে অবাক হওয়ার কিছু নেই।

ফিল্টার তার ইনপুট উপেক্ষা করতে পারে

এই উদাহরণে ইনপুট JSON ডেটা উপেক্ষিত হয় এবং আউটপুটে কোনো প্রভাব ফেলে না:

$ echo '{"answer": 42}' | jq '6 * 9'
54

ফিল্টার ডেটার স্ট্রিম আউটপুট দিতে পারে

একটি ফিল্টার একাধিক মান আউটপুট দিতে পারে। যেমন, .[] ফিল্টার একটি অ্যারে-র প্রতিটি এলিমেন্টকে আলাদা মান হিসেবে আউটপুট দেয়:

$ jq -n -c '[1, 2, 3]'
[1,2,3]

$ jq -n -c '[1, 2, 3] | .[]'
1
2
3

এমন একটি _ফিল্টার_কে অন্যটিতে পাইপ করলে দ্বিতীয় ফিল্টার-টি প্রতিটি মানের জন্য চালিত হবে:

$ jq -n -c '[1, 2, 3] | .[] | . * 2'
2
4
6

এটি অনেকটা অন্তর্নিহিত ইটারেশনের মতো। এই কৌশলটি একবার বুঝে গেলে দেখবেন, খুব শক্তিশালী jq _ফিল্টার_ও বেশ সংক্ষিপ্ত হতে পারে।

প্রথম বন্ধনী

প্রথম বন্ধনী দিয়ে সাব-এক্সপ্রেশনগুলো একসাথে দলবদ্ধ করা হয়, যাতে অপারেশনের ক্রম নিশ্চিত হয়, ঠিক অন্য ভাষাগুলোর মতোই। jq-তে এগুলোর প্রয়োজনীয়তা কিছুটা অপ্রত্যাশিত লাগতে পারে।

যেমন, ধরুন আমরা ২টি এলিমেন্টের একটি অ্যারে বানাতে চাই: ৯-এর বর্গমূল; আর ১ ঘাতে উন্নীত e। দুটি আলাদা এক্সপ্রেশন হলো 9 | sqrt আর 1 | exp। আমরা আশা করব আউটপুট হবে অ্যারে [3, 2.7...]

$ jq -n '[ 9|sqrt, 1|exp ]'
[
  20.085536923187668,
  2.718281828459045
]

আমরা যা আশা করেছিলাম তা পাইনি কেন? jq এটাকে এভাবে ব্যাখ্যা করে:

[ ((9|sqrt), 1) | exp ]

jq দুটি এলিমেন্টের (3 আর 1) একটি স্ট্রিম তৈরি করে, যেগুলোর প্রত্যেকটিকে exp-কে দেওয়া হয়।

আমাদের নিশ্চিত করতে হবে যে exp ইনপুট হিসেবে কেবল একটি সংখ্যা নেয়। অর্থাৎ, কমার আগে পাইপটি মূল্যায়িত হয় তা নিশ্চিত করতে হবে।

$ jq -n '[ 9|sqrt, (1|exp) ]'
[
  3,
  2.718281828459045
]

ফাংশন ও অপারেটর

বেশ গভীরে না গিয়েই (ফাংশন নিয়ে বিস্তারিত আলোচনা আরেকটি অনুশীলনীতে হবে), এখানে কয়েকটি কাজের বিল্ট-ইন ফাংশন দেওয়া হলো:

  • length

    ইনপুট হিসেবে একটি অ্যারে পেলে, অ্যারেটিতে থাকা এলিমেন্টের সংখ্যা আউটপুট দেয়।

    $ jq -n '[10, 20, 30, 40] | length'
    4
    
  • +

    এই অপারেটরটি তার অপারেন্ডের টাইপ অনুযায়ী ভিন্ন ভিন্ন কাজ করে: সংখ্যা যোগ করে, স্ট্রিং জোড়া লাগায়, অ্যারে যুক্ত করে, অবজেক্ট একত্র করে।

    $ jq -c -n '
        3 + 4,
        "foo" + "bar",
        ["a", "b"] + ["c"],
        {"m": 10} + {"n": 20}
    '
    7
    "foobar"
    ["a","b","c"]
    {"m":10,"n":20}
    

    add একটি ফাংশন, যা একটি অ্যারে নিয়ে +-এর নিয়মে সব এলিমেন্ট একসাথে যোগ করে একটি মান রিটার্ন করে। [1, 2, 3] | add আউটপুট দেয় 6.

  • map

    ইনপুট হিসেবে একটি অ্যারে আর আর্গুমেন্ট হিসেবে একটি ফিল্টার পেলে, এমন একটি অ্যারে আউটপুট দেয় যেখানে প্রতিটি এলিমেন্টে ফিল্টারটি প্রয়োগ করা হয়েছে

    $ jq -c -n '[10, 20, 30, 40] | map(. / 5)'
    [2,4,6,8]
    
  • select

    কিছু ইনপুট আর আর্গুমেন্ট হিসেবে একটি ফিল্টার পেলে:

    • আর্গুমেন্টে প্রয়োগ করা ফিল্টারের ফল যদি ট্রু হয়, তবে ইনপুট অপরিবর্তিত আউটপুট দেয়
    • নাহলে কিছুই আউটপুট দেয় না (null মানটি নয়, সত্যিই কোনো আউটপুট নয়)

    যেমন, কিছু সংখ্যা দেওয়া থাকলে, ৩ দিয়ে বিভাজ্য সংখ্যাগুলো বেছে নিন

    $ jq -n 'range(10) | select(. % 3 == 0)'
    0
    3
    6
    9
    

    মনে রাখবেন, range সংখ্যার একটি স্ট্রিম আউটপুট দেয়। প্রতিটি সংখ্যার জন্য select একবার করে কল করা হবে। কেবল যে সংখ্যাগুলো এক্সপ্রেশনটি "পাস" করে সেগুলোই আউটপুটে আসে।

    আপনাকে প্রায়ই একটি অ্যারের এলিমেন্ট বেছে নিতে হয়। এটি করার কয়েকটি উপায় আছে।

    ["Anne", "Bob", "Cathy", "Dave"] ইনপুট দিলে, যে নামগুলোর দৈর্ঘ্য ৪ সেগুলো বেছে নিন।

    • map আর select একসাথে ব্যবহার করুন

      map(select(length == 4))
      
    • অ্যারেটিকে ভেঙে এলিমেন্টে পরিণত করুন, ওই স্ট্রিমে select করুন, তারপর ফলাফলগুলো একত্র করুন

      [ .[] | select(length == 4) ]
      

মন্তব্য

মন্তব্য # অক্ষর দিয়ে শুরু হয় আর লাইনের শেষ পর্যন্ত চলতে থাকে।

নির্দেশনা

হঠাৎ আপনার প্যানকেক খেতে খুব ইচ্ছে করছে। আধুনিক ও প্রযুক্তি-মনস্ক একজন মানুষ হিসেবে আপনি প্যানকেকের উপকরণের একটি কেনাকাটার তালিকা JSON ফরম্যাটে লেখেন। তালিকার গঠনটি হলো:

{
  "name": "name of shopping list",
  "ingredients": [ ...list of ingredients... ],
  "optional ingredients": [ ...list of ingredients... ]
}

একটি উপকরণকে JSON অবজেক্ট দিয়ে এভাবে প্রকাশ করা হয়:

{
  "item": "flour",
  "amount": {
    "quantity": 2,
    "unit": "cup"
  }
}

একটি উপকরণে "substitute" নামের একটি ঐচ্ছিক প্রপার্টি থাকতে পারে, যেখানে থাকে এমন আরেকটি জিনিসের স্ট্রিং যা এর বদলে ব্যবহার করা যায়।

চলুন দেখি jq দিয়ে কেনাকাটার তালিকাটি কীভাবে খতিয়ে দেখা যায়

1. কেনাকাটার তালিকার নাম বের করুন

এমন একটি এক্সপ্রেশন লিখুন যা কেনাকাটার তালিকার "name" এলিমেন্টটি আউটপুট দেয়।

2. কতগুলো উপকরণ দরকার তা গুনুন

শুধু "আবশ্যক" উপকরণগুলোই গুনুন। ঐচ্ছিক উপকরণগুলো ধরবেন না।

3. কতটা চিনি?

এমন একটি এক্সপ্রেশন লিখুন যা চিনির পরিমাণ আউটপুট দেয়। শুধু সংখ্যার অংশটুকুই দরকার।

4. যে উপকরণগুলো বদলে ব্যবহার করা যায় সেগুলো ম্যাপ করুন

কিছু উপকরণ বদলে ব্যবহার করা যায় (যদি আপনার কাছে X উপকরণ না থাকে, তাহলে Y ব্যবহার করতে পারেন)। প্রস্তাবিত উপকরণকে তার বিকল্পের সঙ্গে ম্যাপ করা একটি JSON অবজেক্ট আউটপুট দিন। ম্যাপিংয়ের মধ্যে ঐচ্ছিক উপকরণগুলোও রাখুন।

GitHub-এর মাধ্যমে সম্পাদনা করুন লিংকটি একটি নতুন উইন্ডো বা ট্যাবে খোলে
jq Exercism

শপিং লিস্ট শুরু করতে প্রস্তুত?

Exercism-এ সাইন আপ করুন, jq ট্র্যাকের 12টি কনসেপ্ট75টি অনুশীলনী আর সত্যিকারের মানুষের মেন্টরিং দিয়ে শিখুন ও দক্ষ হয়ে উঠুন, সম্পূর্ণ বিনামূল্যে।