जिसने भी Python इस्तेमाल किया है, उसने लगभग निश्चित रूप से लिस्ट कॉम्प्रिहेंशन का इस्तेमाल किया होगा। Python के शुरुआती वर्शन से ही यह उसके सिंटैक्स का अहम हिस्सा रहा है।
इतनी सुविधाजनक चीज़ धीरे-धीरे दूसरी भाषाओं में भी अपनी जगह बना लेती है, और Julia उनमें से एक है।
Julia प्रोग्रामर के लिए कॉम्प्रिहेंशन ज़रूरत नहीं, बल्कि एक विकल्प है, क्योंकि आम तौर पर इसके दूसरे तरीके भी मौजूद होते हैं (ब्रॉडकास्टिंग, हायर-ऑर्डर फंक्शन, वगैरह)।
लेकिन कई बार कॉम्प्रिहेंशन ऐरे बनाने का एक आसान, पढ़ने लायक और तेज़ तरीका देता है। इसे इस्तेमाल करना या न करना अंत में आपकी निजी पसंद पर निर्भर है, और इस पर भी कि आप Python और फंक्शनल भाषाओं के बारे में क्या सोचते हैं।
इसका सिंटैक्स ज़्यादातर Python की सीधी नकल है, लेकिन इसमें बहु-आयामी ऐरे के लिए कुछ अतिरिक्त सुविधाएँ जोड़ी गई हैं।
बहुत हद तक Python जैसा, जिसमें वैकल्पिक if क्लॉज़ भी शामिल है।
julia> [x^2 for x in 1:3]
3-element Vector{Int64}:
1
4
9
julia> [x^2 for x in 1:3 if isodd(x^2)]
2-element Vector{Int64}:
1
9
आउटपुट का आकार कॉम्प्रिहेंशन के ब्यौरे पर निर्भर करता है: आसान मामलों में यह आम तौर पर इनपुट कलेक्शन जैसा ही होता है, लेकिन if क्लॉज़ लगने पर यह सपाट होकर एक Vector बन जाता है।
julia> m
2×3 Matrix{Int64}:
1 2 3
4 5 6
julia> [x^2 for x in m]
2×3 Matrix{Int64}:
1 4 9
16 25 36
julia> [x^2 for x in m if isodd(x^2)]
3-element Vector{Int64}:
1
25
9
Python की तरह हम एक से ज़्यादा for क्लॉज़ लिख सकते हैं, जिनमें अलग-अलग वेरिएबल हों और इनपुट कलेक्शन एक जैसे या अलग-अलग हों।
julia> [x * y for x in 1:3 for y in 4:6]
9-element Vector{Int64}:
4
5
6
8
10
12
12
15
18
julia> [x * y for x in 1:3 for y in 4:6 if isodd(x * y)]
2-element Vector{Int64}:
5
15
यह नेस्टेड लूप के बराबर है। आउटपुट एक-आयामी होता है, चाहे इनपुट मैट्रिक्स ही क्यों न हो।
julia> m
2×3 Matrix{Int64}:
1 2 3
4 5 6
julia> [x*y for x in m for y in m]
36-element Vector{Int64}:
1
4
2
5
(truncated output...)
पिछले हिस्से में हमने ऐसे कई for क्लॉज़ देखे, जो सिर्फ स्पेस से अलग किए गए थे।
इस हिस्से में सिर्फ एक for है और वेरिएबल को कॉमा से अलग किया जाता है।
julia> [(x, y) for x in 1:3, y in 4:6]
3×3 Matrix{Tuple{Int64, Int64}}:
(1, 4) (1, 5) (1, 6)
(2, 4) (2, 5) (2, 6)
(3, 4) (3, 5) (3, 6)
कॉम्प्रिहेंशन का हर वेरिएबल आउटपुट में एक नया आयाम बनाता है, और वेरिएबल के हर संभव संयोजन के लिए एक एंट्री होती है।
ऊपर के उदाहरण में x पंक्तियों में नीचे की ओर बढ़ता है और y कॉलमों में दाएँ की ओर। और भी ऊँचे आयाम संभव हैं, पर आउटपुट की पठनीयता को लेकर वही आम चेतावनियाँ लागू रहती हैं।
पिछले हिस्सों में हमने ऐरे आउटपुट पर ध्यान दिया, जहाँ कॉम्प्रिहेंशन ब्रैकेट [ ... ] के अंदर लिखा जाता है।
जब इन ब्रैकेट की जगह कोष्ठक ( ... ) लगाए जाते हैं, तो कुछ अलग होता है: हमें एक generator expression मिलता है, यानी एक लेज़ी इटरेटर, जो ज़रूरत पड़ने पर अगली वैल्यू देता है।
julia> g = ((x, y) for x in 1:3, y in 4:6)
Base.Generator{Base.Iterators.ProductIterator{Tuple{UnitRange{Int64}, UnitRange{Int64}}}, var"#9#10"}(var"#9#10"(), Base.Iterators.ProductIterator{Tuple{UnitRange{Int64}, UnitRange{Int64}}}((1:3, 4:6)))
# Indexing fails with a generator, the entries don't exist yet
julia> g[1, 2]
ERROR: MethodError: no method matching getindex(::Base.Generator{Base.Iterators.ProductIterator{Tuple{UnitRange{…}, UnitRange{…}}}, var"#9#10"}, ::Int64, ::Int64)
# conversion to array
julia> collect(g)
3×3 Matrix{Tuple{Int64, Int64}}:
(1, 4) (1, 5) (1, 6)
(2, 4) (2, 5) (2, 6)
(3, 4) (3, 5) (3, 6)
# generators are mainly designed for iteration
julia> [i * j for (i, j) in g]
3×3 Matrix{Int64}:
4 5 6
8 10 12
12 15 18
जब कॉम्प्रिहेंशन का नतीजा तुरंत आगे की प्रोसेसिंग में इस्तेमाल होता है, तो जनरेटर मेमोरी बचाने वाला हो सकता है, क्योंकि उसे बीच का कोई बड़ा ऐरे संग्रहीत करने की ज़रूरत नहीं पड़ती।
फंक्शन के आर्गुमेंट के तौर पर इस्तेमाल होने वाले जनरेटर को अलग से कोष्ठक लगाने की ज़रूरत नहीं होती।
# inefficient
julia> v = [x^2 for x in 1:1e6];
julia> sum(v)
3.333338333335e17
# better - use a generator
julia> sum(x^2 for x in 1:1e6)
3.3333383333312755e17
जनरेटर का सिंटैक्स कॉम्प्रिहेंशन जैसा ही होता है, बस चारों ओर लगे ब्रैकेट का फर्क होता है।
डिक्शनरी कंस्ट्रक्टर में भी जनरेटर काम आ सकते हैं।
julia> Dict(x => x^2 for x in 1:5)
Dict{Int64, Int64} with 5 entries:
5 => 25
4 => 16
2 => 4
3 => 9
1 => 1
आप एक ऑनलाइन फैशन बुटीक स्टोर में काम करते हैं। आपके मन में वेबसाइट के एक फीचर का विचार आता है, जिसमें उपयोगकर्ता को पोशाकें सुझाई जाती हैं। यहाँ ध्यान संभावित पोशाकों, उनकी कीमतों और टकराने वाले विकल्पों को हटाने पर है।
इन समस्याओं को हल करने के अलग-अलग तरीके हो सकते हैं, लेकिन इन सबको एक कॉम्प्रिहेंशन से हल किया जा सकता है।
clothingitem() को ऐसे बनाइए कि वह दो Tuple ले: एक categories का और दूसरा उनसे जुड़ी qualities का।
फंक्शन को एक Dict लौटाना चाहिए, जिसमें की categories हों और वैल्यू qualities हों।
julia> categories = ("item_name", "price", "color", "base_color");
julia> qualities = ("Descriptive Name", 99.00, "Ochre Red", "red");
julia> clothingitem(categories, qualities)
Dict{String, Any} with 4 entries:
"price" => 99.0
"item_name" => "Descriptive Name"
"base_color" => "red"
"color" => "Ochre Red"
आपका फंक्शन कितनी भी संख्या में categories संभाल सके, ऐसा होना चाहिए।
get_combinations() को ऐसे बनाइए कि वह टॉप का एक Tuple और बॉटम का एक Tuple ले।
फंक्शन को उन टपलों का cartesian product एक 2-D ऐरे (यानी Matrix) के रूप में लौटाना चाहिए।
हर एंट्री एक (top, bottom) कॉम्बिनेशन होती है, जो एक Tuple है।
पंक्तियों में नीचे जाने पर टॉप बदलते हैं, और स्तंभों में आगे बढ़ने पर बॉटम बदलते हैं।
julia> tops = (
Dict("item_name" => "Dress shirt"),
Dict("item_name" => "Casual shirt")
);
julia> bottoms = (
Dict("item_name" => "Jeans"),
Dict("item_name" => "Dress trousers")
);
julia> get_combinations(tops, bottoms)
2×2 Matrix{Tuple{Dict{String, String}, Dict{String, String}}}:
(Dict("item_name"=>"Dress shirt"), Dict("item_name"=>"Jeans")) (Dict("item_name"=>"Dress shirt"), Dict("item_name"=>"Dress trousers"))
(Dict("item_name"=>"Casual shirt"), Dict("item_name"=>"Jeans")) (Dict("item_name"=>"Casual shirt"), Dict("item_name"=>"Dress trousers"))
कपड़े की हर चीज़ के साथ एक price फील्ड जुड़ी होती है, इसलिए पोशाकों की पूरी कीमत की तुलना कर पाना काम आ सकता है।
get_prices() बनाइए, जो कपड़ों के कॉम्बिनेशन का एक ऐरे लेता है।
फंक्शन को उसी आकार का ऐरे लौटाना चाहिए, जिसमें हर पोशाक की कीमत अपनी-अपनी जगह पर हो।
julia> tops = (
Dict("item_name" => "Dress shirt", "base_color" => "blue", "price" => 35),
Dict("item_name" => "Casual shirt", "base_color" => "black", "price" => 20)
);
julia> bottoms = (
Dict("item_name" => "Jeans", "base_color" => "blue", "price" => 30),
Dict("item_name" => "Dress trousers", "base_color" => "black", "price" => 75)
);
julia> combomatrix = get_combinations(tops, bottoms);
julia> get_prices(combomatrix)
2×2 Matrix{Int}::
65 110
50 95
julia> filteredmatrix = filter_clashing(combomatrix)
1-element Vector{Tuple{Dict{String, Any}, Dict{String, Any}}}:
(Dict("price" => 20, "item_name" => "Casual shirt", "base_color" => "black"), Dict("price" => 30, "item_name" => "Jeans", "base_color" => "blue"))
julia> get_prices(filteredmatrix)
1-element Vector{Int}:
50
कपड़े की हर चीज़ में एक base_color फील्ड होती है।
इस फील्ड का इस्तेमाल करके वे सारे कॉम्बिनेशन हटाइए जिनमें टॉप और बॉटम का बेस कलर एक ही हो।
filter_clashing() को ऐसे बनाइए कि वह कपड़ों के कॉम्बिनेशन का एक ऐरे ले।
मेल खाने वाले कॉम्बिनेशन का एक 1-D ऐरे (यानी Vector) लौटाइए।
julia> tops = (
Dict("item_name" => "Dress shirt", "base_color" => "blue", "price" => 35),
Dict("item_name" => "Casual shirt", "base_color" => "black", "price" => 20)
);
julia> bottoms = (
Dict("item_name" => "Jeans", "base_color" => "blue", "price" => 30),
Dict("item_name" => "Dress trousers", "base_color" => "black", "price" => 75)
);
julia> combos = get_combinations(tops, bottoms);
julia> filter_clashing(combos)
1-element Vector{Tuple{Dict{String, Any}, Dict{String, Any}}}:
(Dict("price" => 20, "item_name" => "Casual shirt", "base_color" => "black"), Dict("price" => 30, "item_name" => "Jeans", "base_color" => "blue"))
Exercism पर साइन अप कीजिए और Julia को 35 कॉन्सेप्ट128 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।