გაკვეთილი 3 – Data Structures

მონაცემთა სტრუქტურები

ეს გაკვეთილი და თემა ამ კურსში ერთ-ერთი ყველაზე დიდი და მნიშნველოვანია. ბევრმა ახალმა ინფორმაციამ შეიძლება დაგაბნიოთ, შეიძლება პირველ ცდაზე ყველაფერი ნათელი არ იყოს, მაგრამ აქ საშიში და უსწავლელი არაფერია, ნუ შეშინდებით! “Practice makes it perfect”. თუ რაიმე გაუგებარია, გთხოვთ დასვით კითხვები.
techademy logo

მესამე გაკვეთილის თემაა მონაცემთა სტრუქტურები. ეს იქნება ფაქტიურად წინა გაკვეთილის გაგრძელება, რადგნა მონაცემთა სტრუქტურები შეგვიძლია როგორც რთული მონაცემთა ტიპები ისე წარმოვიდგინოთ. აქამდე თითო ცვლადში მხოლოდ ერთი მონაცემის შენახვა შეგვეძლო. მაგალითად x = 6 ან name = “Dato”. მაგრამ პითონს გაცილებით მეტი შეუძლია. ამ გაკვეთილში ვნახავთ, თუ როგორ შეგვიძლია არაერთი (თეორიულად უსასრულო რაოდენობის) მონაცემის შენახვა ერთ ცვლადში – მონაცემთა სტრუქტურების საშუალებით. განვიხილავთ ოთხ სხვადასხვა ასეთ მონაცემთა სტრუქტურას:

  • List – “სია”
  • Set – “სიმრავლე”
  • Tuple – “ტუპლი”
  • Dictionary – “ლექსიკონი”

List – “სია”

ლისტი ანუ სია ყველაზე ხშირად გამოყენებადი და მძლავი რთული მონაცემთა ტიპი – ანუ სტრუქტურაა პითონში.

მისი შექმნა შემდეგნრირად ხდება: mylist = []

ამ სინტაქსით შევქმენით ახლა ცვლადი, რომელსაც ჰქვია mylist და იგი არის ცარიელი ლისტი ამჟამად. ლისტში შეგვიძლია რამდენიც გვინდა, იმდენი მონაცემი (თუნდაც სხვადასხვა ტიპის) კვადრატულ ფრჩხილებში ჩავწეროთ და ისინი მძიმის საშუალებით გამოვყოთ.

numbers = [1, 2, 3, 4]

ლისტში არსებულ მონაცემებს ასევე ეწოდებათ ლისტის ელემენტები. 

მნიშვნელოვანია გავითვალისწინოთ, რომ ლისტი არის ე.წ. “დალაგებული” (ordered) სტრუქტურა, რაც იმას ნიშნავს, რომ მისი ელემენტები ყოველთვის ინარჩუნებენ თავიანთ ადგილს, თუ ჩვენ არ მოვახდენიეთ რაიმე ცვლილებები. თუ რთულია იმის წარმოდგენა, თუ რას ვგულისხმობ, არაუშავს – ეს უფრო ნათელი გახდება, როდესაც Set სქტრუქტურას განვიხილავთ.

ამ შემთხვევაში გვაქვს ცვლადი numbers, რომელიც არის ლისტის ტიპის და შეიცავს ოთხ ელემენტს – 1, 2, 3, 4 – ხოლო თითოეული მათგანი არის int მონაცემი – ანუ მთელი რიცხვი. ლისტის ეკრანზე გამოტანა print-ის საშუალებით შეგვიძლია, ზუსტად ისე როგორც წინა გაკვეთილში მარტივ ცვლადებზე გავაკეთეთ.

ნებისმიერ ლისტის ელემენტზე წვდომა მისი ინდექსის საშუალებითაა შესაძლებელი. 

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

ეს ანალოგია იმედია წარმოდგენაში დაგეხმარებათ, მაგრამ პითონის სიასა და ბარსელონას შორის ორი დიდი განსხვავებაა: 

  1. ინდექსირება იწყება 0-დან, და არა 1-დან.
  2. ინდექსი ავტომატურად იზრდება ერთით და ინდექსის გამოტოვება შეუძლებელია

ახლა გადავთარგმნოთ ეს ადამიანურ ენაზე. ფეხბუთში არ არსებობს ნომერი 0, ისევე როგორც ჩვენ საგნის დათვლას არ ვიწყებთ 0-ით, არამედ 1-ით. მაგრამ პითონში – და ასევე მრავალ პროგრამირების ენაში – ათვლა იწყება 0-დან. შესაბამისად პირველი ელემენტი ლისტში, დგას 0 ინდექსზე.

ლისტს ასევე გააჩნია ზომა, უფრო კონკრეტულად სიგრძე – length. ლისტის სიგრძე მისი ელემენტების რაოდენობის ტოლია, ჩვენს მაგალითში ანუ 4. 

ამის შემოწმება მარტივად len() ფუნქციით შემდეგნაირად შეგვიძლია: len(numbers).

ინდექსის საშუალებით კი ნებისმიერ ლისტის ელემენტზე გვაქვს წვდომა. დავუშვათ თუ გვინდა, რომ ჩვენი numbers ლისტიდან რიცხვი 3 გამოვიყენოთ, ამისათვის საჭიროა ვიცოდეთ, თუ რომელ ინდექსზე/პოზიციაზე დგას რიცხვი 3 ლისტში, თუ შევხედავთ ზემოთ არსებულ სურათს, დავინახავთ, რომ ეს არის ინდექს 2-ზე. ლისტიდან ინდექსის საშუალებით ელემენტზე წვდომა შემდეგნაირად ხდება: numbers[2] – ეს დაგვიბრუნებს უკან ლისტ numbers-ში მეორე ინდექსზე/პოზიციაზე არსებულ ელემენტს, ანუ ამ შემთხვევაში 3-ს.

ლისტის რამდენიმე დამახასიათებელი თვისება აუცილებელია კარგად ვიცოდეთ. ესენია:

  • ლისტის ცვლადია – ანუ მასში ცვლილებების შეტანა შეგვიძლია
  • შესაძლებელია შეიცავდეს დუპლიკატ მონაცემებს/ელემენტებს
  • შეუძლია სხვადასხვა ტიპის მონაცემების ერთად შენახვა

თითოეულ ამ თვისებას ახლა ვნახავთ მაგალითის საშუალებით. 

ლისტის ნებისმიერ ინდექსზე შეგვიძლია შევცვალოთ მონაცემი. ამჟამად მეორე ინდექსზე დგას რიცხვი 3 – როგორც უკვე ვნახეთ ზემოთ. ეს რიცხვი 3 შეგვიძლია ნებისმიერი მონაცემით ჩავანაცვლოთ, მაგალითად რიცხვი 1-ით. ეს შემდეგნაირად ხდება: numbers[2] = 1

ანუ რა მოხდა აქ? 

ჩვენ ავიღეთ ელემენტი მეორე ინდექსზე და მასში მონაცემი 1 შევინახეთ, ისევე როგორც ცვლადს მივანიჭებდით რაღაც ინფორმაციას. ანუ ამით შევცვალეთ ლისტი და იგი ახლა შეიცავს შემდეგ ელემენტებს: [1, 2, 1, 4]

აქვე ცხადად ჩანს, რომ შესაძლებელია ლისტი დუპლიკატ მონაცემებს შეიცავდეს – რიცხვი 1 ორჯერ წერია.

ლისტს ასევე შეგვიძლია ახალი ელემენტი append() ფუნქციის საშუალებით დავამატოთ. ეს შენდეგნაირად ხდება: numbers.append(“Dato”)

ამ ბრძანებით დავამატეთ ლისტში ახალი ელემენტი: “Dato”. ახლად დამატებული ელემენტი append() ფუნქციის საშუალებით, ყოველთვის ლისტის ბოლოში ემატება. ანუ ამჟამად numbers ლისტი შეიცავს შემდეგ ინფორმაციას: [1, 2, 1, 4, “Dato”] – ამითი ისიც ვაჩვენეთ, რომ ლისტს შეუძლია სხვადასხვა ტიპის მონაცემები შეინახოს. ამ შემთხვევაში – მთელი რიცხვები და ტექსტი. ამ ოპერაციის შედეგად ჩვენ რა თქმა უნდა ლისტის ზომაც ანუ სიგრძეც შევცვალეთ და იგი ამჟამად 5-ია. 

ანალოგიურად შეგვიძლია ლისტის ელემენტის წაშლა, ამისათვის შეგვიძლია გამოვიყენოთ append()-ის საპირისპირო ფუნქცია pop(). თუ უბრალოდ numbers.pop() დავწერთ, ეს წაშლის ლისტის ბოლო ელემენტს ავტომატურად. მაგრამ ასევე შეგვიძლია pop-ს არგუმენტად გადავცეთ ის იქდექსი, თუ რომლის წაშლაც გსურს. მაგ: numbers.pop(1).

იმ შემთხვევაში, თუ გვსურს რომელიმე კონკრეტული ელემენტის წაშლა, მაგრამ არ ვიცით მისი ინდექსი, ამისათვის შეგვიძლია remove() ფუნქცია გამოვიყენოთ. remove() ფუნქციას აუცილებელია გადავცეთ არგუმენტად ის ელემენტი, რომლის წაშლაც გვსურს.

მაგალითად: გვაქვს ლისტი fruits = [“Apple”, “Banana”, “Orange”]

Banana ელემენტის წაშლა შემდეგნაირად შეგვიძლია: fruits.remove(“Banana”)

ლისტი – ანუ სია –  ძალიან მძლავრი და სასარგებლო სტრუქტურაა. მისი მანიპულირება კი კარგად უნდა შეგვეძლოს. მომავალ გაკვეთილებში და პროექტებში არაერთ მნიშნველოვან ტექნიკას გავეცნობით ლისტის მანიპულაციისა და სასურველი მონაცემების ხელმისაწვდომად.

Set – “სიმრავლე”

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

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

“დაულაგებელი” (unordered) – ეს იმას ნიშნავს, რომ მისი შექმნის შემდეგ, როდესაც მას გამოვიძახებთ, მისი ელემენტები შეიძლება სხვადასხვა მიმდევრობით იყოს სიმრავლეში. მაგ: names = {“Dato”, “Nika”, “Ana”, “Elene”}. თუ ჩვენ მოგვიანებით გამოვიძახებთ ან სიმრავლეს, მისი ელემენტები რანდომიზირებული თანმიმდევრობით იქნება, მაგ: {“Nika”, “Ana”, “Dato”, “Elene”}. აქედან გამომდინარე შეუძლებელია სიმრავლის ელემენტებზე ინდექსით წვდომა. რადგან მათ არ აქვთ ფიქსირებული ინდექსი/პოზიცია.

“უცვლელი” (Unchangeable) – ანუ ლისტისგან განსხვავებით სიმრავლის ელემტების შეცვლა არ შეგვიძლია, მაგრამ ახალი ელემენტების დამატება შესაძლებელია, ამისათვის არსებობს add() ფუნქცია. ხოლო ელემენტის წასაშლელად .remove() ფუნქცია. 

შეუძლებელია დუპლიკატი ელემენტების ქონა – ლისტისაგან განსხვავებით, სიმრავლე არ ინახავს დუპლიკატ ელემენტებს, თუ მას გადავცეთ დუპლიკას, სიმრავლე ავტომატურად “გაფილტრავს” ამას და უგულებელყოფს, შეინახავს მხოლოდ ერთ ინსტანსს. მაგ. თუ დავწერთ myset = {“Dato”, “Ana”, “Nika”, “Dato”} იგი რეალურად შეიცავს შემდეგ ელემენტებს: {“Dato”, “Ana”, “Nika”} ანუ დათო არ მეორდება.

იხილეთ მაგალითები: 

სიმრავლის ზომის/სიგრძის შემოწმება, ისევე როგორც ლისტის – len() ფუნქციითაა შესაძლებელი.

სიმრავლის ერთ-ერთი მნიშნველოვანი დამახასიათებელი ფუნქციაა union() რისი მეშვეობითაც შეგვიძლია ორი სიმრავლე გავაერთიანოთ და იგი მესამე, ახალ სიმრავლეში შევინახოთ. მაგალითად:

names = {“Dato”, “Ana”}

numbers = {1, 2}

names_numbers = names.union(numbers)

მოგვცემს ახალ სიმრავლეს, რომელსაც ჰქვია names_numbers და შეიცალვს შემდეგ ელემენტებს {“Dato”, “Ana”, 1, 2} (გაითვალისწინეთ, რომ ელემენტების თანმიმდევრობა ცვალებადია)

იგივე ეფექტის მიღზევა update() ფუნქციაა შესაძლებელი, დიდი განსხვავება ისაა, რომ update ფუნქცია პირველ სიმრავლეს გააერთიანებს მეორე სიმრავლესთან, და ან გაერთიანებას პირველ სიმრავლეში ინახავს. union() ფუნქცია კი ახალ სიმრავლეს ქმნიდა.

names.update(numbers) ამ შემთხვევაში ცვლადი names შეიცავს იგივე ელემენტებს რასაც names_numbers ზედა მაგალითიდან.

სავარჯიშოები

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

ყველა სავარჯიშო თავისი პასუხებით შეგიძლიათ გადმოწეროთ .zip ფაილად


გადმოწერა

#1 – Reverse a List / ლისტის ელემენტების რევერსირება


პასუხი

#2 – Insert Element in a Nested List / ელემენტის დამატება საბლისტში


პასუხი

#3 – Find and Replace an Element in a list / იპოვეთ და ჩაანაცვლეთ ელემენტი ლისტში


პასუხი


წინა გაკვეთილი


კურსზე დაბრუნება


შემდეგი გაკვეთილი