Sunday, July 19, 2015

თავი 9 (9 - 9,1)



თავი 9

ლექსიკონები

ლექსიკონი არის როგორც სია, მაგრამ უფრო ზოგადი(general). სიაში პოზიციები(a.k.a. ინდექსები) უნდა იყოს მთელი რიცხვი, ხოლო ლექსიკონში  ინდექსი შეიძლება იყოს(თითქმის) ყველა ტიპი. ლექსიკონზე შეგიძლია იფიქრო, როგორც ინდექსების (რასაც ეძახიან გასაღებს - keys) და მნიშვნელობების კავშირზე (mapping). ყოველი გასაღები(key) მიუთითებს მნიშვნელობაზე. გასაღების და მნიშვნელობის კავშირს ჰქვია გასაღები - მნიშვნელობა წყვილი(გმწ) ან ელემენტი(item).
მაგალითისთვის  გავაკეთებთ ლექსიკონს, რომელიც ინგლისურიდან გადაიყვანს ესპანურზე. გასაღებები და მნიშვნელობები არის სტრინგი,
ფუნქცია dict აკეთებს ახალ ლექსიკონს ელემენტის გარეშე. dict არის ჩაშენებული ფუნქციის სახელი, ამიტომ ეს სახელი ცვლადს არ დაარქვა.

>>> eng2sp = dict()
>>> print eng2sp
{}


ტალღოვანი ფრჩხილები (squiggly-brackets), {}, წარმოადგენს ცარიელ ლექსიკონს. ლექსიკონში ელემენტის დასამატებლად შეგიძლია გამოიყენო კვადრატული ფრჩხილები:

>>> eng2sp['one'] = 'uno'

ეს ხაზი აკეთებს ელემენტს რომელიც მიმართავს გასაღებს 'one' მნიშვნელობა 'uno' - სკენ. ლექსიკონს თუ კიდევ ამოვბეჭდავთ, დავინახავთ გმწ - ს გასაღებსა და მნიშვნელობას შორის ორწერტილით:

>>> print eng2sp
{'one': 'uno'}

ამონაბეჭდის ეს ფორმა ასევე არის შესატანი (input) ფორმატით. მაგალითად, შეგიძლია გააკეთო ახალი ლექსიკონი სამი ელემენტით:

>>> eng2sp = {'one': 'uno', 'two': 'dos', 'three': 'tres'}

მაგრამ eng2sp - ს თუ ამობეჭდავ დარჩები გაკვირვებული:

>>> print eng2sp
{'one': 'uno', 'three': 'tres', 'two': 'dos'}


გმწ - ს თანრიგი არ არის ყოველთვის ერთი და იგივე. შენს კომპიუტერში თუ აკრიფავ იგივე მაგალითს, შეიძლება მიიღო განსხვავებული შედეგი, მაგრამ ეს არაა პრობლემა, იმიტომ რომ ლექსიკონის ელემენტები არასდროსაა ინდექსირებული მთელი რიცხვებით. სანაცვლოდ გამოიყენე გასაღები სათანადო მნიშვნელობის სანახავად:

>>> print eng2sp['two']
'dos'

გასაღები ’two’ ყოველთვის მიუთითებს მნიშვნელობაზე 'dos', ასე რომ ელემენტების თანრიგს მნიშვნელობა აღარ აქვს. ლექსიკონში გასაღები თუ არ არის, მაშინ მიიღებ შემდეგ გამოსახულებას:

>>> print eng2sp['four']
KeyError: 'four'

len ფუნქცია ლექსიკონებზე მუშაობს და აბრუნებს გმწ - ს რაოდენობას:

>>> len(eng2sp)
3

in ოპერატორი მუშაობს ლექსიკონებზე; ამით შეგიძლია გაიგო ლექსიკონში რომელია გასაღები (appearing as a value is not good enough).

>>> 'one' in eng2sp
True
>>> 'uno' in eng2sp
False

ლექსიკონში მნიშვნელობების სანახავად შეგიძლია გამოიყენო values მეთოდი, რომელიც აბრუნებს მნიშვნელობებს, როგორც სიას და შემდეგ გამოიყენე in ოპერატორი:

>>> vals = eng2sp.values()
>>> 'uno' in vals
True'

in ოპერატორი სიისთვის და ლექსიკონისთვის იყენებს განსხვავებულ ალგორითმებს. სიისთვის იყენებს ძებნის ხაზოვან(linear) ალგორითმს. სია რაც უფრო დიდია,  ძებნის დროც უფრო დიდია - სიის სიგრძის პროპორციულად. ლექსიკონებისთვის პითონი იყენებდეს hash table - , რასაც აქვს შესანიშნავი თვისება. in ოპერატორს მიაქვს ერთნაირი დრო და არ აქვს მნიშვნელობა რამდენი ელემენტია ლექსიკონში. არ აგიხსნით თუ რატომაა hash ფუნქცია ასეთი ჯადოსნური, თუმცა ამის შესახებ შეგიძლია აქ წაიკითხო wikipedia.org/wiki/Hash_table
სავარჯიშო9.1 დაწერე პროგრამა რომელიც კითხულობს სიტყვებს words.txt - ში და  ლექსიკონში ალაგებს როგორც გასაღებებს. არ აქვს მნიშვნელობა თუ რა მნიშვნელობა ექნება გასაღებებს.  შემდეგ შეგიძლია გამოიყენო in ოპერატორი რომ შეამოწმო არის თუ არა სტრინგი ლექსიკონში.

9.1 ლექსიკონები როგორც მთვლელების კომპლექტი

დავუშვათ გაქვს სტრინგი და გინდა დათვალო თითოეული ასო რამდენჯერაა გამოყენებული. ამის გასაკეთებლად რამდენიმე გზაა:

1.  შეგიძლია გააკეთო 26 ცვლადი. ანბანის ყოველი ასოსთვის - ერთი. შემდეგ შეგიძლია გააკეთო სტრინგის გადაკვეთა და ყოველი ასოსთვის გაზარდო შესაბამისი მთვლელი სავარაუდოდ მიჯაჭვული პირობითობის გამოყენებით.
2.  შეგეძლო გაგეკეთებინა სია 26 ელემენტით და გადაგეკონვერტირებინა ყოველი ასო ციფრში(ord ჩაშენებული ფუნქციის გამოყენებით) და ციფრების როგორც სიის ინდექსების გამოყენებით მთვლელი გაგეზრდა.
3.  შეგეძლო გაგეკეთებინა ლექსიკონი, რომელსაც გასაღებებად ექნებოდა სიმბოლოები და მნიშვნელობებად - მთვლელები. პირველად როცა დაინახავდი სიმბოლოს, დაამატებდი ელემენტს ლექსიკონში და ამის შემდეგ გაზრდიდი არსებული ელემენტის მნიშვნელობას.

თითოეული ასრულებს ერთი და იგივე გამოთვლას, მაგრამ იყენებენ  გამოთვლის განსხვავებულ ხერხებს. განხორციელება არის დათვლის შესრულების ხერხი. ზოგი ასეთი ხერხი სხვაზე უკეთესია. მაგალითად, ლექსიკონის განხორციელების უპირატესობა ისაა, რომ არ გვჭირდება წინასწარ ვიცოდეთ რომელი ასოები გამოჩნდება სტრინგში.  მარტო ადგილი უნდა შევქმნათ  იმ ასოებისთვის, რომელიც გამოჩნდება.
ასე შეიძლება გამოიყურებოდეს კოდი:

word = 'brontosaurus'
d = dict()
for c in word:
            if c not in d:
                        d[c] = 1
            else:
                        d[c] = d[c] + 1
print d


რეალურად ვითვლით ჰისტოგრამას, რომელიც არის სტატისტიკური ტერმინი მთვლელების კომპლექტის. for მარყუჟი კვეთს სტრინგს, მარყუჟში ყოველ ჯერზე სიმბოლო c თუ არ არის ლექსიკონში, ვაკეთებთ ახალ ელემენტს გასაღებით c და ვაძლევთ მნიშვნელობას 1 (მას შემდეგ, რაც ეს ასო უკვე ვნახეთ). c თუ არის ლექსიკონში, მაშინ ვზრდით d[c].
აქაა პროგრამის შედეგი:

{'a': 1, 'b': 1, 'o': 2, 'n': 1, 's': 2, 'r': 2, 'u': 2, 't': 1}

ჰისტოგრამა მიუთითებს, რომ ასოები ’a’ და  'b' ჩანს ერთხელ; 'o' ჩანს ორჯერ და.ა.შ.
ლექსიკონებს აქვს მეთოდი get რომელიც იღებს გასაღებს და საწყის  მნიშვნელობას. ლექსიკონში გასაღები  თუ ჩანს, get აბრუნებს შესაბამის მნიშვნელობას; სხვა შემთხვევაში აბრუნებს საწყის  მნიშვნელობას. მაგალითად:

>>> counts = { 'chuck' : 1 , 'annie' : 42, 'jan': 100}
>>> print counts.get('jan', 0)
100
>>> print counts.get('tim', 0)
0

შეგვიძლია გამოვიყენოთ get ჰისტოგრამის მარყუჟის უფრო მოკლედ დასაწერად. get მეთოდი ავტომატურად ითვალისწინებს შემთხვევას, როცა  გასაღები არაა ლექსიკონში, ამიტომ შეგვიძლია შევამციროთ ხაზების რაოდენობა და ამოვაგდოთ  if ბრძანება.

word = 'brontosaurus'
d = dict()
for c in word:
      d[c] = d.get(c,0) + 1
print d

get მეთოდის გამოყენება მთვლელის მარყუჟის გასამარტივებლად არის ძალიან ხშირად გამოყენებადი პითონის "სტილი"("idiom) და ჩვენ ხშირად გამოვიყენებთ წიგნის დანარჩენ ნაწილში. შეგიძლია გამოყო დრო და მარყუჟი, რომელიც იყენებს if ბრძანებას და in ოპერატორს შეადარო მარყუჟს, რომელიც იყენებს get მეთოდს. ორივე აკეთებს ზუსტად იგივეს, მაგრამ ერთი არის უფრო მოკლე.