العمليات علي المصفوفات
الدالة map
يتم تطبيق الفلتر علي جميع عناصر المصفوفة
وهو مكافئ لتطبيق [.[] | filter]
$ echo [1, 2, 3] | jq 'map(.+1)'
[2, 3, 4]
// equivalent to:
$ echo [1, 2, 3] | jq '[.[] | . +1]'
[2, 3, 4]
$ echo '{"a": 1, "b": 2, "c": 3}' | jq 'map(.+1)'
[2, 3, 4]عند تطبيق map علي object فانه تم تطبيق الفلتر علي قيم الـ object ورجع بمصفوفة, ولارجاع object بدلا من ذلك يمكن استخدام map_values
$ echo '{"a": 1, "b": 2, "c": 3}' | jq 'map_values(.+1)'
{"a": 2, "b": 3, "c": 4}تطبيق map أو map_values علي مصفوفة سيعطي دائما نفس النتيجة
تطبيق map علي مصفوفة او object دائما يعطي مصفوفة
تطبيق map_values علي object يعطي object
يمكن لـ map أن تأخذ عدة فلاتر وستقوم بتطبيق جميع الفلاتر علي كل عنصر
أما map_value ستقوم بتطبيق أول فلتر فقط علي جميع العناصر
$ echo [1, 2, 3] | jq 'map(. , . + 10)'
[1, 11, 2, 12, 3, 13]
$ echo [1, 2, 3] | jq 'map_values(. , . + 10)'
[1, 2, 3]
$ echo '{"a": 1, "b": 2, "c": 3}' | jq 'map(. , . + 10)'
[1, 11, 2, 12, 3, 13]
$ echo '{"a": 1, "b": 2, "c": 3}' | jq 'map_values(. , . + 10)'
{"a": 1, "b": 2, "c": 3}ويمكن اضافة جميع عناصر المصفوفة الي بعضهم البعض باستخدام add
$ echo '[1, 2, 3]' | jq add
6
$ echo '["a", "b", "c"]' | jq add
"abc"
$ echo '[]' | jq add
null
$ echo '[{"a":3}, {"a":5}, {"b":6}]' | jq 'add'
{"a": 5, "b": 6}
$ echo '[{"a":3}, {"a":5}, {"b":6}]' | jq 'map(.a) | add'
8
# or
$ echo '[{"a":3}, {"a":5}, {"b":6}]' | jq 'add(.[].a)'
8حذف عنصر من مصفوفة أو object باستخدام del
$ echo '{"foo": 42, "bar": 9001, "baz": 42}' | jq 'del(.foo)'
{"bar": 9001, "baz": 42}
$ echo '["foo", "bar", "baz"]' | jq 'del(.[1, 2])'
["foo"]
// equivalent to (using Subtraction `-`):
$ echo '["foo", "bar", "baz"]' | jq '. - [.[1], .[2]]'
["foo"]اختيار العناصر التي تحقق شروط معينة باستخدام select
الدالة select تأخذ شرط محدد وتقوم بارجاع قيمة boolean, عندما تقوم بارجاع true يتم اختيار العنصر, وعندما تقوم بارجاع false يتم حذف العنصر
$ echo '[1,5,3,0,7]' | jq '.[] | select(. > 2)'
5
3
7
$ echo '[1,5,3,0,7]' | jq '[.[] | select(. > 2)]'
[5, 3, 7]
$ echo '[1,5,3,0,7]' | jq 'map(select(. >= 2))'
[5, 3, 7]
$ echo '[{"id": "first", "val": 1}, {"id": "second", "val": 2}]' | jq '.[] | select(.id == "second")'
{"id": "second", "val": 2}ويمكن اختيار العناصر حسب نوعها باستخدام arrays, objects, iterables, booleans, numbers, normals, finites, strings, nulls, values, scalars
$ echo '[[],{},1,"foo",null,true,false]' | jq '.[] | numbers'
1
$ echo '[[],{},1,"foo",null,true,false]' | jq '.[] | strings'
"foo"
$ echo '[[],{},1,"foo",null,true,false]' | jq '.[] | arrays'
[]
$ echo '[[],{},1,"foo",null,true,false]' | jq '.[] | objects'
{}
$ echo '[[],{},1,"foo",null,true,false]' | jq '.[] | booleans'
true
false
$ echo '[[],{},1,"foo",null,true,false]' | jq '.[] | scalars'
1
"foo"
null
true
false
$ echo '[[],{},1,"foo",null,true,false]' | jq '.[] | normals'
1
$ echo '[[],{},1,"foo",null,true,false]' | jq '.[] | finites'
1
$ echo '[[],{},1,"foo",null,true,false]' | jq '.[] | nulls'
nullويمكن استخدام any والتي تقوم بارجاع true اذا أي من عناصر المصفوفة حقق الشرط
أو all والتي تقوم بارجاع true فقط في حالة أن جميع عناصر المصفوفة حققوا الشرط
$ echo [true, false] | jq any
true
$ echo [false, false] | jq any
false
$ echo [] | jq any
false
$ echo [1, 2, 3] | jq 'any(. > 2)'
true
$ echo [1, 2, 3] | jq 'any(. > 3)'
falseتسطيح عناصر المصفوفة باستخدام flatten
اذا كانت المصفوفة تحتوي علي عناصر متداخلة يمكن جعلها flat باستخدام الدالة flatten
$ echo [1, [2], [[3]]] | jq flatten
[1,2,3]
$ echo [1, [2], [[3]]] | jq 'flatten(1)'
[1, 2, [3]]
$ echo [[]] | jq flatten
[]ترتيب عناصر المصفوفة باستخدام sort أو sort_by
يتم ترتيب عناصر المصفوفة حسب الترتيب التالي:
nullfalsetruenumbers
strings, in alphabetical order (by Unicode codepoint value)
arrays, in lexical order
objects
بالنسبة للـ objects يتم أولا مقارنة الـ keys وفي حالة تساوي مفتاحين يتم الترتيب حسب الـ values
ويمكن استخدام sort_by للترتيب حسب مفتاح معين
يمكن لـ sort_by ان تعطي أكثر من نتيجة وفي هذه الحالة يتم الترتيب بالنتيجة الأولي وفي حالة تساوي القيم يتم الترتيب بالقيمة التالية وهكذا.
$ echo [8,3,null,6] | jq sort
[null,3,6,8]
$ echo '[{"foo":4, "bar":11}, {"foo":5, "bar":10}, {"foo":2, "bar":1}]' | jq 'sort'
[{"foo":2,"bar":1},{"foo":5,"bar":10},{"foo":4,"bar":11}]
$ echo '[{"foo":4, "bar":11}, {"foo":5, "bar":10}, {"foo":2, "bar":1}]' | jq 'sort_by(.foo)'
[{"foo":2,"bar":1},{"foo":4,"bar":11},{"foo":5,"bar":10}]
$ echo '[{"foo":4, "bar":11}, {"foo":5, "bar":10}, {"foo":2, "bar":1}]' | jq 'sort_by(.bar)'
[{"foo":2,"bar":1},{"foo":5,"bar":10},{"foo":4,"bar":11}]
$ echo '[{"foo":4, "bar":11}, {"foo":5, "bar":10}, {"foo":2, "bar":1}]' | jq 'sort_by(.bar, .foo)'
[{"foo":2,"bar":1},{"foo":5,"bar":10},{"foo":4,"bar":11}]
$ echo '[{"foo":4, "bar":11}, {"foo":5, "bar":10}, {"foo":2, "bar":1}]' | jq 'sort_by(.foo, .bar)'
[{"foo":2,"bar":1},{"foo":4,"bar":11},{"foo":5,"bar":10}]تطبيق عملي: يمكن مثلا استخدام هذه الميزة لترتيب حقول ملف package.json
تقسيم مصفوفة الي مجموعات حسب قيمة عنصر معين باستخدام group_by
$ echo '[{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}]' | jq 'group_by(.foo)'
[
[ {"foo": 1, "bar": 10}, {"foo": 1, "bar": 1} ], //<--- group 1 (foo=1)
[ {"foo": 3, "bar": 100} ] //<--- group 2 9foo=3)
]
ايجاد أصغر أو أكبر قيمة
يمكن ايجاد أصغر أو أكبر قيمة باستخدام min, max, min_by(path_exp), max_by(path_exp)
$ echo '[5,4,2,7]' | jq min
2
$ echo '[5,4,2,7]' | jq max
بالنسبة للـ objects يتم الترتيب بالمفاتيح أولا ثم بالقيم
$ echo '[{"foo":1, "bar":14}, {"foo":2, "bar":3}]' | jq min
{
"foo": 2,
"bar": 3
}تم أولا عمل ترتيب داخلي لكل object
{"bar":14, "foo":1}
{"bar":3, "foo":2}ثم مقارنة المفاتيح, وفي حالة تساوي المفاتيح يتم مقارنة القيم
وهنا نجد أن bar:3 أصغر من bar: 14 لذا يتم اختيار هذا العنصر علي أنه الاصغر وتكون النتيجة {"foo":2, "bar":3}
ويمكن تحديد حقل معين أو أكثر للترتيب عن طريقه
$ echo '[{"foo":1, "bar":14}, {"foo":2, "bar":3}]' | jq 'min_by(.foo)'
{"foo": 1, "bar": 14}
$ echo '[{"foo":1, "bar":14}, {"foo":2, "bar":3}]' | jq 'min_by(.bar)'
{"foo": 2, "bar": 3}أزالة العناصر المكررة
عند استخدام unique أو uniqu_by يتم ترتيب العناصر مع ازالة العناصر المكررة
$ echo '[1,2,5,3,5,3,1,3]' | jq unique
[1,2,3,5]
$ echo '[{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}]' | jq unique
[{"foo":1,"bar":2},{"foo":1,"bar":3},{"foo":4,"bar":5}]
$ echo '[{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}]' | jq 'unique_by(.foo)'
[{"foo":1,"bar":2},{"foo":4,"bar":5}]
$ echo '[{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}]' | jq 'unique_by(.bar)'
[{"foo":1,"bar":2},{"foo":1,"bar":3},{"foo":4,"bar":5}]
$ echo '["chunky", "bacon", "kitten", "cicada", "asparagus"]' | jq 'unique_by(length)'
["bacon","chunky","asparagus"]اعكاس ترتيب عناصر المصفوفة باستخدام reverse
$ echo '[1,2,3,4]' | jq reverse
[4,3,2,1]التحقق من وجود عنصر معين داخل المصفوفة باستخدام contains
$ echo '["a", "b", "c"]' | jq 'contains(["a"])'
true
$ echo '["a", "b", "c"]' | jq 'contains(["a", "b"])'
true
$ echo '["a", "b", "c"]' | jq 'contains(["a", "b", "d"])'
false
// strings
$ echo '"abcd"' | jq 'contains("ab")'
true
// objects
//
$ echo '{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}' | jq 'contains({foo: 12, bar: [{barp: 12}]})'
true
$ echo '{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}' | jq 'contains({foo: 12})'
trueويمكن اجراء العملية العكسية باستخدام inside أي التحقق أن عنصر ما يحتوي عنصر اخر, وهو عكس contains
// checking that the array includes "a"
$ echo '["a", "b", "c"]' | jq 'contains(["a"])'
true
// checking that "a" is inside the array
$ echo '["a"]' | jq 'inside(["a", "b", "c"])'
trueويمكن ايجاد أماكن وجود العنصر داخل المصفوفة باستخدام indices
او الاكتفاء بمكان أول تواجد فقط باستخدام index أو اخر مكان باستخدام rindex
$ echo '[0,1,2,1,3,1,4]' | jq 'indices(1)'
[1,3,5]
$ echo '"abcda"' | jq 'indices("a")'
[0,4]
$ echo '[0,1,2,3,1,4,2,5,1,2,6,7]' | jq 'indices(1, 2)'
[1,4,8]
[2,6,9]
$ echo '[0,1,2,1,3,1,4]' | jq 'index(1)'
1
$ echo '[0,1,2,1,3,1,4]' | jq 'rindex(1)'
5الحصول علي توليفات عدة مصفوفات باستخدام combinations
تخيل أن معنا مصفوفتان [1,2] و [3,4] ونريد توليف مصفوففات منها, سنأخذ كل عنصر من عناصر المصفوفة الاولي مع كل عنصر من عناصر المصفوفة الثانية في مصفوفة كالتالي
1 → 3
1 → 4
2 → 3
2 →4
وتكون النتيجة هي المصفوفات التي تشكلت معنا من هذه التوليفة
وفي حالة وجود رقم داخل cominations() فانه يتم توليد مصفوفات كل واحدة مكونة من هذا العدد من العناصر
مثلا لو عندنا مصفوفة [0,1] وقمنا بتطبيق combinations(2) عليها, يتم تكوين مجموعة من المصفوفات طول كل واحدة منهم 2 عنصر
وتكون كل الاحتمالات كالتالي:
المصفوة الاولي تتكون من العنصر الاول فقط مكرر بالعدد المطلور (2) وبالتالي يكون لدينا [0,0]
المصفوفة الثانية تكون باستبدال عنصر واحد فقط مع العنصر التالي في المصفوفة الاصلية وبالتالي يكون لدينا [0,1]
ثم تكرار الاستبدال تدريجيا بنفس المنطق حتي نصل الي مصفوفة كلها من العنصر الثاني فقط من المصفوفة الاصلية, أي [1,1]
ولفهم الفكرة أكثر, دعنا تجرب combinations(3) علي نفس المصفوفة [0,1]
نريد تكوين مجموعة مصفوفات كل واحدة منها مكونة من 3 عناصر, أول مصفوفة مكونة من العنصر الاول فقط, ثم يتم الاستبدال التدريجي مع العنصر الثاني حتي نحصل علي مصفوفة مكونة من العنصر الثاني فقط
أول مصفوفة مكونة من العنصر الاول فقط مكرر 3 مرات [0,0,0]
يتم استبدال عنصر واحد فقط بالعنصر الثاني في المصفوفة الاصلية [0,0,1]
يتم استبدال عنصر واحد فقط مرة ثانية [0,1,0] ثم [1,0,0]
ونستمر في الاستبدال حتي نصل الي [1,1,1]
$ echo [[1,2], [3, 4]] | jq 'combinations'
[1,3]
[1,4]
[2,3]
[2,4]
$ echo [0, 1] | jq 'combinations(0)'
[]
$ echo [0, 1] | jq 'combinations(1)'
[0]
[1]
$ echo [0, 1] | jq 'combinations(2)'
[0,0]
[0,1]
[1,0]
[1,1]
$ echo [0, 1] | jq 'combinations(3)'
[0,0,0]
[0,0,1]
[0,1,0]
[0,1,1]
[1,0,0]
[1,0,1]
[1,1,0]
[1,1,1]
$ echo [0, 1] | jq 'combinations(4)'
[0,0,0,0]
[0,0,0,1]
[0,0,1,0]
[0,0,1,1]
[0,1,0,0]
[0,1,0,1]
[0,1,1,0]
[0,1,1,1]
[1,0,0,0]
[1,0,0,1]
[1,0,1,0]
[1,0,1,1]
[1,1,0,0]
[1,1,0,1]
[1,1,1,0]
[1,1,1,1]
$ echo [[1,2], [3, 4]] | jq 'combinations(1)'
[[1,2]]
[[3,4]]
$ echo [[1,2], [3, 4]] | jq 'combinations(2)'
[[1,2],[1,2]]
[[1,2],[3,4]]
[[3,4],[1,2]]
[[3,4],[3,4]]نأتي هنا للسؤال المهم, كيف نستفيد من هذه الميزة في المشاريع الحقيقية؟
في الحقيقة يوجد عدة استخدامات مفيدة جدا منها علي سبيل المثال:
في الاختبارات: نريد مثلا توليد test cases مكونة من كل الاحتمالات الممكنة, مثلا لدينا نظام تشغيل Windows ونظام Linux ونظام Mac وكذلك لدينا متصفحات مختلفة, ونريد اجراء الاختبار الخاص بنا علي كل المتصفحات في كل الانظمة, أي نريد مثلا التجربة علي متصفح Chrome علي نظام Windows و Linux و Mac ثم تجربة Firefox بنفس الطريقة ثم Edge بنفس الطريقة وهكذا
وبالتالي يمكن تطبيق شئ كالتالي
echo '[ ["Windows", "Linux", "Mac"], ["Chrome", "Firefox", "Edge"] ]' | jq 'combinations(2)'في الـ debugging يمكن مثلا تجربة النظام بالكامل مع تفعيل توليفات مختلفة من المميزات للتحقق أن الخطأ يظهر في حالات معينة
echo '["on", "off"]' | jq 'combinations(3)'
[on,on,on] //<--- enable all features
[on,on,off] //<-- enable all features except the last one
...ويمكن ايضا الاستفادة منها في حل الألغاز, مثلا في لعبة الشطرنج نريد حصر كل الاحتمالات الممكنة لكل قطعة, مثلا يمكن لقطعة ما التحرك في اتجاه ما أو اخر وفي كل اتجاه يمكن أن يتحرك عدد معين من الخطوات
وكذلك في البيزنس لمعرفة كل القرارات الممكنة, أو في مضاربات البورصة لمعرفة كل الاحتمالات, أو في data analysis لمعرفة كل الاحتمالات الممكنة
وفي مجال الذكاء الصناعي يمكن استخدامها في عمليات NLP preprocessing