diff --git a/School.java b/School.java new file mode 100644 index 0000000..e55c414 --- /dev/null +++ b/School.java @@ -0,0 +1,105 @@ +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import acm.program.ConsoleProgram; + +public class School extends ConsoleProgram { + ArrayList teachers; + ArrayList subjects; + ArrayList students; + + Map> teachSubj; + Map> subjPupils; + + public School() { + teachers = new ArrayList(); + subjects = new ArrayList(); + students = new ArrayList(); +## + teachSubj = new HashMap<>(); + subjPupils = new HashMap<>(); + } + + public void addTeacher(String teacher) { + teachers.add(teacher); + teach.put(teacher, null); + } + + public void addSubject(String teacher, String subject) { + if (teachers.contains(teacher)) { + if (teachSubj.get(teacher) == null) { + ArrayList helper = new ArrayList(); + teachSubj.put(teacher, helper); + } + if (!teachSubj.get(teacher).contains(subject)) { + teachSubj.get(teacher).add(subject); + } + if (!subjects.contains(subject)) { + subjects.add(subject); + } + } + } + + public void addPupil(String pupil, String subject) { + if (subjects.contains(subject)) { + if (subjPupils.get(subject) == null) { + ArrayList helper = new ArrayList(); + subjPupils.put(subject, helper); + } + + subjPupils.get(subject).add(pupil); + + students.add(pupil); + } + } + + public Iterator getTeachers(String pupil) { + if (students.contains(pupil)) { + ArrayList result = new ArrayList(); + for (String teacher : teachSubj.keySet()) { + ArrayList subj = teachSubj.get(teacher); + if (subj != null) { + for (int i = 0; i < subj.size(); i++) { + ArrayList pupils = subjPupils.get(subj.get(i)); + if (pupils != null) { + if (pupils.contains(pupil)) { + result.add(teacher); + break; + } + } + } + } + } + return result.iterator(); + } + return null; + } + + public Iterator getPupils(String teacher) { + if (teachers.contains(teacher)) { + ArrayList result = new ArrayList(); + + ArrayList subj = teachSubj.get(teacher); + if (subj != null) { + for (int i = 0; i < subj.size(); i++) { + ArrayList pupils = subjPupils.get(subj.get(i)); + if(pupils != null){ + for (int j = 0; j < pupils.size(); j++) { + result.add(pupils.get(j)); + } + } + } + } + return result.iterator(); + } + return null; + } + + public void removeTeacher(String teacher) { + teachers.remove(teachers.indexOf(teacher)); + teachSubj.remove(teacher); + } +} \ No newline at end of file diff --git a/School.md b/School.md new file mode 100644 index 0000000..ea0c6d1 --- /dev/null +++ b/School.md @@ -0,0 +1,275 @@ +# School + +პრობლემა: + +``` +თქვენი მიზანია დაწეროთ School კლასი, რომლის საშუალებითაც შევძლებთ +უნივერსიტეტის მართვას. კლასს უნდა ჰქონდეს კონსტრუქტორი და 5 public მეთოდი. + +public School() +კონსტრუქტორს არაფერი არ გადაეცემა. აქ შეგიძლიათ ინიციალიზაცია გაუკეთოთ +თქვენთვის საჭირო ცვლადებს. + +public void addTeacher(String teacher) +addTeacher მეთოდის საშუალებით შეგიძლიათ სკოლას დაამატოთ ახალი +მასწავლებელი. მეთოდს გადაეცემა მასწავლებლის სახელი. შეგიძლიათ ჩათვალოთ, +რომ მასწავლებლის სახელი უნიკალურია. + +public void addSubject(String teacher, String subject) +addSubject მეთოდის საშუალებით შეგიძლიათ მასწავლებელს დაუმატოთ საგანი. +მეთოდს გადაეცემა მასწავლებლის სახელი და საგნის სახელი. ჩათვალეთ, რომ საგნის +სახელი უნიკალურია. ერთი და იგივე მასწავლებელი შეიძლება რამდენიმე საგანს +კითხულობდეს, ასევე ერთსა და იმავე საგანს შეიძლება რამდენიმე მასწავლებელი +კითხულობდეს ერთდროულად. +თუკი teacher სახელის მქონე მასწავლებელი არ არის აქამდე დამატებული, მაშინ +მეთოდმა არაფერი არ უნდა გააკეთოს. + +public void addPupil(String pupil, String subject) +addPupil მეთოდის საშუალებით შეგიძლიათ საგანზე დაამატოთ მოსწავლე. ერთი და +იგივე მოსწავლე შეიძლება ერთ ან რამდენიმე საგანს სწავლობდეს. + +public Iterator getTeachers(String pupil) +getTeachers მეთოდს გადაეცემა მოსწავლის სახელი და მან უნდა დააბრუნოს ამ +მოსწავლის ყველა მასწავლებელზე იტერატორი. ანუ მხოლოდ იმ მასწავლებლების +სახელები, რომლებიც ასწავლიან იმ საგნებს, რომლებზეც მოსწავლეა +დამატებული(სწავლობს). თუკი pupil სახელის მოსწავლე არ გვყავს მაშინ მეთოდმა +უნდა დააბრუნოს null. + +public Iterator getPupils(String teacher) +getPupils მეთოდს გადაეცემა მასწავლებლის სახელი და მან უნდა დააბრუნოს ამ +მასწავლებლის ყველა სტუდენტზე იტერატორი. ანუ მხოლოდ იმ სტუდენტების +სახელები, რომლებიც მის რომელიმე საგანს სწავლობენ. თუკი teacher სახელის მქონე +ლექტორი არ გვყავს მაშინ მეთოდმა უნდა დააბრუნოს null. + +public void removeTeacher(String teacher) +მეთოდმა უნდა წაშალოს მასწავლებლის შესახებ ყველა ინფორმაცია. ამ მეთოდის +გამოძახების, შემდეგ getTeachers მეთოდმა არ უნდა დააბრუნოს teacher სახელი არც +ერთი სტუდენტისთვის. +``` + +## პრობლემის გააზრება: + +ჩვენ უნდა დავწეროთ კლასი, რომელიც შეასრულებს რაღაც ბრძანებებს (სულ გადმოგვეცემა 7 მეთოდი), რომელიც უკავშირდება მასწავლებლებს, მოსწავლეებს და საგნებს. ეს ამოცანა დაგვეხმარება, რომ უკეთ გავეცნოთ სხვადასხვა კოლექციებს, თუ როგორ და რა დროს უნდა გამოვიყენოთ ისინი. + +## პრობლემის გადაჭრის გზა: + +მოგეხსენებათ, ჩვენი კლასი შეიცავს რამდენიმე მეთოდს. სწორედ ამიტომ ჯობია, თითოეული მათგან ცალ-ცალკე ამოვხსნათ. + +## `School()` მეთოდი: + +School კლასში მეთოდების გარეთ აღწერილი მაქვს 3 `ArrayList()`: +```java + ArrayList teachers; //ინახავს მასწავლებლების სიას + ArrayList subjects; //ინახავს საგნების სიას + ArrayList students; //ინახავს სტუდენტების/მოსწავლეების სიას +``` +და აღწერილი მაქვს 2 Map: +```java + Map> teachSubj; //მასწავლებლები და საგნები, რომელსაც ასწავლის + Map> subjPupils;//საგნები და მოსწავლეები, რომლებიც ამ საგანს სწავლობენ +``` + +## `public School()` მეთოდი: + ინიციალიზაციას ვუკეთებთ კოლექციებს, რომლებიც მეთოდების გარეთ შევქმენით. ის, თუ რაში დაგვჭირდება ეს კოლექციები, ამას ამოხსნის მომენტში კარგად გავეცნობით. + +## `addTeacher(String teacher)` მეთოდი: + +ეს მეთოდი მარტივი დასაწერია. რას ვშვრებით როცა მასწავლებელი გვემატება? ლოგიკური იქნება, თუ მას ჩავსვავთ მასწავლებლების სიაში: + +```java + teachers.add(teacher); +``` +* მასწავლებელი კიდევ მონაწილეობს `Map` ში, რომელშიც აღწერილია მისი დამოკიდებულება საგნების მიმართ, რომელსაც ის ასწავლის: + +```java + teachSubj.put(teacher, null); +``` +* რატომ `null`? ეს კარგი კითხვაა. ჩვენ მასწავლებელს უნდა გადავცეთ `null`, რადგან ის ჯერ არცერთ საგანს არ ასწავლის. + +* უკეთესი ვარიანტი იქნებოდა, თუ ჩვენ მას გადავცემდით ცარიელ ლისტს (`new ArrayList()`), რადგან როდესაც ჩვენ მოგვიხდება რაღაც მეთოდები გამოვიძახოთ მასწავლებლის საგნების სიაზე აღარ მოგვიწეს იმის შემოწმება ეს სია `null` ია თუ არა. + +## `addSubject(String teacher, String subject)` მეთოდი: + +* ამ მეთოდში მასწავლებლის საგნების სიას უნდა დავუმატოთ ახალი საგანი, თუ ის მას უკვე შეიცავს მაშინ არაფერი უნდა ვქნათ, რადგან ის არაფერს შეცვლის გარდა იმისა, რომ ტყუილად დაიკავებს ადგილს ლისტში. + +* პირველ რიგში, შევამოწმოთ, მოიძებნება თუ არა ეს მასწავლებელი მასწავლებლების სიაში (თუ არა არაფერი ვქნათ მაშინ) და სწორედ აქ გამოჩნდება ის, თუ რაში გვჭირდება მასწავლებლების სია: + +```java + if (teachers.contains(teacher)) +``` +* დავუშვათ მოიძებნა ასეთი მასწავლებელი, რა უნდა გავაკეთოთ ახლა? ბევრი იტყოდა, რომ ახლა დროა უკვე დავამატოთ საგანი მასწავლებელს, რაც არასწორია! რადგან ჩვენ ჯერ უნდა შევამოწმოთ ამ კონკრეტული მასწავლებლის საგნების სია არის თუ არა `null`, წინააღმდეგ შემთხვევაში ამოგვიგდებდა error -ს თუ შევეცდებოდით `null` ზე რაღაც ოპერაციების ჩატარებას. თუ `null` ია მაშინ ჩავამატოთ ამ მასწავლებლის სიაში ახალი ცარიელი ლისტი: + +```java + if (teachSubj.get(teacher) == null) { + ArrayList helper = new ArrayList(); + teachSubj.put(teacher, helper); + } +``` + +* ამის შემდგომ კი ჩვენ შეგვიძლია ჩავამატოთ ახალი საგანი მასწავლებლის სიაში, თუ ეს საგანი არ არის უკვე მასწავლებლის სიაში არსებული: + +```java + if (!teachSubj.get(teacher).contains(subject)) { + teachSubj.get(teacher).add(subject); + } +``` + +* ეს მეთოდი მორჩა, თუმცა ჩვენ ვალდებულები ვართ შევინახოთ ახალი საგანი subject ების სიაში, თუ ის არ არსებობს: + +```java + if (!subjects.contains(subject)) { + subjects.add(subject); + } +``` + +## `addPupil(String pupil, String pupil)` მეთოდი: + +* საგანზე ამატებს მოსწავლეს + +* პირველ რიგში, შევამოწმოთ არსებობს თუ არა საერთოდ ასეთი საგანი(თუ არ არის, მაშინ არაფერი მოვიმოქმედოთ). სწორედ აქ დავინახავთ იმას თუ რაში დაგვჭირდა შეგვექმნა საგნების სია: + +```java + if (subjects.contains(subject)) +``` + +* თუ ესეთი საგანი არსებობს, მაშინ ჯერ უნდა შევამოწმოთ ამ საგნის მოსწავლეების სია `null` არის თუ არა, როგორც ეს გავაკეთეთ `(addSubject)` მეთოდში. თუ არის, მაშინ ჯერ შევქმნათ ცარიელი ლისტი, ჩავამატოთ `subjPupils` მაპში შესაბამის საგანთან და ამის შემდგომ დავუმატოთ მოსწავლე. + +```java + if (subjPupils.get(subject) == null) { + ArrayList helper = new ArrayList(); + subjPupils.put(subject, helper); + } + + subjPupils.get(subject).add(pupil); +``` + +* ეს მეთოდიც დაიწერა, თუმცა აქაც შევინახოთ ახალი დამატებული მოსწავლე მოსწავლეების სიაში, თუ რატომ ვაკეთებთ ამას? ამას ქვემოთ ნახავთ: + +```java + students.add(pupil); +``` + +## `Iterator getTeachers(String pupil)` მეთოდი: + +* ეს მეთოდი გამოირჩევა სხვა უკვე დაწერილი მეთოდებისაგან მისი კომპლექსურობით. მეთოდმა უნდა დააბრუნოს იტერატორი იმ მასვწავლებლების სიაზე, რომლებიც გადმოცემულ მოსწავლეს ასწავლიან. + +* აქ კი უნდა დავსვათ კითხვა, როგორ შევძლებთ ამას ჩვენი კოლექციებით? (სჯობს ამაზე ცოტა ხანს თავად იფიქროთ). + +გთავაზობთ შემდეგ გზას: გადავუყვეთ ყველა მასწავლებლის სიას, თითოეული მასწავლებლისათვის გადავუყვეთ იმ საგნების სიას, რომელსაც ეს მასწავლებელი ასწავლის და შემდეგ თითოეული საგინასთვის გადავუყვეთ მოსწავლეების სიას, რომლებიც ამ საგანს სწავლობენ. თუ გადმოცემული მოსწავლე შეგვხვდა, მაშინ დავამატოთ მასწავლებელი სიაში, თუ არა ძებნდა განვაგრძოთ. + +იმედია ამოხსნა გასაგებია, მაგრამ აქ კიდევ უნდა დავფიქრდეთ იმაში თუ როგორ დავწერთ ზემოთხსენებულ ამოხსნას კოდით (ქვემოთ განვიხილავთ). + +* გადავიდეთ კოდის რეალიზაციაზე: + +* პირველ რიგში, შევამოწმოთ არსებობს თუ არა ასეთი მოსწავლე ჩვენს სკოლაში (თუ არ არის, მაშინ ჩვენმა მეთოდმა უნდა დააბრუნო null). აქ დავინახავთ იმას, თუ რატომ დაგვჭირდა მოსწავლეების სიის შექმნა: + +```java + if (students.contains(pupil)) +``` +* თუ ასეთი მოსწავლე მართლაც არსებობს, მაშინ შევქმნათ ცარიელი ლისტი `ArrayList result` სადაც შევინახავთ მასწავლებლების სიას, რომლებიც გადმოცემულ მოსწავლეს ასწავლიან. + +* გადავუყვეთ თითოეულ მასწავლებელს `teachSubj` მაპში (რომელიც წარმოადგენს მასწავლებლებისა და საგნებს შორის ურთიერთდამოკიდებულებას) და თითოეული მასწავლებლისათვის ამოვიღოთ საგნების სია, რომელსაც ისინი ასწავლიან: + +```java + for (String teacher : teachSubj.keySet()) + ArrayList subj = teachSubj.get(teacher); +``` + +* თუ საგნების სია `null` ია, ცხადია, რომ ეს მასწავლებელი უეჭველად არ მოხვდება `result` ში. სწორედ ამიტომ გადავდივართ შემდეგ მასწავლებელზე. თუ `null` არაა, მაშინ გადავუყვეთ საგნებს და თითოეული მათგანისათვის ამოვიღოთ მოსწავლეების სია, რომლებიც ამ საგანს სწავლობენ. + +```java + for (int i = 0; i < subj.size(); i++) + ArrayList pupils = subjPupils.get(subj.get(i)); +``` + +* მაშ, რაღა დაგვრჩენია? დავწეროთ ამ მოსწავლეების სიებისთვის `contains` ფუნქცია, რომლითაც შევამოწმებთ არის თუ არა გადმოცემული მოსწავლე ამ სიაში. თუ ასე მოვიქცევით, ჩვენ კოდი სწორად არ იმუშავებს, რადგან ჩვენ დაგვავიწყდა თითოეული საგნის მოსწავლეების სიისათვის შეგვემოწმებინა, არის თუ არა ის `null`, თუ არის, მაშინ გადავდივართ შემდეგი საგნის მოსწავლეების სიაზე, თუ არაა შევამოწმოთ მოიცავს თუ არა ის გადმოცემულ მოსწავლესაც: + +```java + if (pupils != null) + if (pupils.contains(pupil)) +``` + +* თუ მოიცავს, მაშინ დავამატოთ მასწავლებელი `result` სიაში და გავაკეთოთ `break` რათა ტყუილად სხვა საგნების მოსწავლეების სიაც არ შევამოწმოთ, რადგან ეს მასწავლებელი უკვე დამატებულია სიაში. ასევე თუ `break` ს არ გავაეკთებთ ზემოხსენებულის გარდა შეიძლება მოხდეს ისეთი რაღაც, როდესაც მასწალვებელი `result` სიას დაემატოს ორჯერ, სამჯერ ან მეტჯერ უფრო. რატომ მოხდება ეს? თუ მოსწავლე ამ მასწავლებლის რამდენიმე საგანს სწავლობს `break` ის გარეშე, ჩვენ ამ მასწავლებელს რამდენჯერმე დავუმატებდით `result` სიას: + +```java + result.add(teacher); + break; +``` + +* ბოლოს ჩვენ უდნა დავაბრუნოთ სიაზე იტერატორი და არა თითონ სია: + +```java + return result.iterator(); +``` + +## `Iterator getPupils(String teacher)` მეთოდი: + +* ეს მეთოდი ძალიან ჰგავს ზემოხსენებულ `Iterator getTeachers(String pupil)` მეთოდს. ამ მეთოდში უნდა დავაბრუნოთ იტერატორი მოსწავლეების იმ სიაზე, რომლებიც ამ გადმოცემული მასწავლებლის საგნებს სწავლობენ. + +* დავსვათ კითხვა, თუ როგორ უნდა მივწვდეთ იმ მოსწავლეების სიას, რომლებიც ამ მასწავლებლის საგნებს სწავლობენ, ჩვენი კოდის მიხედვით? (სჯობს, ამაზე ცოტა ხანს თავად იფიქროთ). + +* მე გთავაზობთ შემდეგს: ამოვიღოთ საგნების სია, რომელსაც ეს მასწავლებელი ასწავლის, შემდეგ გადავუყვეთ საგნების სიას და თითოეული მათგანისათვის გადავუყვეთ მოსწავლეების სიას, რომლებიც ამ საგანს სწავლობენ და დავამატოთ ისინი დასაბრუნებელ `result` ლისტში: + +* სანამ უშუალოდ კოდის მთავარ ეტაპზე გადავალთ, ჯერ უნდა შევამოწმოთ, მოიძებნება თუ არა ეს მასწავლებელი სკოლაში(თუ არ მოიძებნება დავაბრუნოთ `null`), თუ როგორ შევამოწმებთ ამას, თავადაც უკვე მიხვდებით. თუ მოიძებნება ამოვიღოთ შესაბამის საგნების სია: + +```java + if (teachers.contains(teacher)) + ArrayList result = new ArrayList(); //მოსწავლეების სია, რომლებიც გადმოცემული მასწავლებლის საგნებს სწავლობენ. + ArrayList subj = teachSubj.get(teacher); +``` + +* ამის შემდგომ უშუალოდ ვერ გადავუყვებით საგნების სიას, რადგან ჯერ არ ვიცით ის `null` არის თუ არა. თუ ის `null` ია, დავაბრუნოთ ცარიელ ლისტზე იტერატორი, რადგან გამოდის, რომ ეს მასწავლებელი არც ერთ საგანს არ ასწავლის და შესაბამისად არც ერთი ბავშვი სწავლობს ამ მასწავლებლის საგნებს. ხოლო თუ `null` არაა გადავუყვეთ თითოეულ საგანს: + +```java + if (subj != null) + for (int i = 0; i < subj.size(); i++) +``` + +* თითოეული საგნისათვის ჩვენ გვინდა წვდომა გვქონდეს იმ მოსწავლეების სიაზე, რომლებიც ამ კონკრეტულ საგანს სწავლობენ: + +```java + ArrayList pupils = subjPupils.get(subj.get(i)); +``` + +* ალბათ უკვე ყველავ ვხვდებით, რომ სანამ უშუალოდ ამ უკანასკნელის ელემენტებს დავამატებთ `result`-ს ჯერ უნდა შევამოწმოთ ეს უკანასკნელი `null` არის თუ არა. თუ არის, მაშინ გადავიდეთ შემდეგი საგნის მოსწავლეების სიაზე, თუ არა დავამატოთ ამ `pupils` სიაში არსებული მოსწავლეები `result` -ს: + +```java + if(pupils != null){ + for (int j = 0; j < pupils.size(); j++) { + result.add(pupils.get(j)); + } + } +``` + +* შეიძლება ერთი მოსწავლე მასწავლებლის რამდენიმე საგანს სწავლობდეს, სწორედ ამიტომ თუ გინდათ, რომ მისის სახელი არ გამეორდეს ბევრჯრერ `result` სიაში, შეგიძლიათ უბრალოდ სანამ დაამატებთ შეამოწმოთ: + +```java + if(!result.contains(pupils.get(j))) +``` + +* დაბოლოს, დავაბრუნოთ იტერატორი `result` ზე: + +```java + return result.iterator(); +``` + +## `removeTeacher(String teacher)` მეთოდი: + +* ამ მეთოდმა მასწავლებელი უნდა წაშალოს სიიდან (ანუ დავუშვათ ამ მასწავლებელმა შეწტვიტა ამ სკოლაში მუშაობა). + +* ცხადია, რომ მისი ამოშლა მოხდება იმ კოლექციებიდან, რომელშიც არის ჩამატებული. უფრო კონკრეტულად კი, როდესაც მან დაიწყო მუშაობა (addTeacher) რა კოლექციებშიც ჩაემატა ის, იმ კოლექციებიდან უნდა წავშალოთ: + +```java + teachers.remove(teachers.indexOf(teacher)); + teachSubj.remove(teacher); +``` + +## შესაძლო ხარვეზები: + +* ცხადია, რომ როდესაც დიდი კოდის დაწერა გიწევს, ხარვეზებსაც უფრო მეტჯერ გადააწყდებით. ამ ამოცანის მთავარი ხარვეზები: + +* ბევრჯერ დაგვჭირდა იმის შემოწმება არის თუ არა კოლექცია `null`, თუ ამ შემოწმებას არ გააკეთებს თქვენ შესაძლოა `null` ზე ოპერაციები გააკეთოთ რაც არასწორია. + +* როდესაც ბევრ კოლექციებს ვიყენებთ და მითუმეტეს თუ ერთროულად შეიძლება ბევრი კოლექცია გამოვიყენოთ, აუცილებლად უნდა ვაკონტროლოთ მათი ელემენტები და არ უნდა აგვერიოს სხვადასხვა კოლექციის "current index" ები ერთმანეთში, რათა რაღაც კონკრეტული ლისტის საზღვრებს არ გავცდეთ. + +* სანამ მსგავსი სტილის ამოცანის ამოხსნას დაიწყებთ, ჯერ დაგეგმეთ თუ როგორ და სად შეინახავთ ინფორმაციას. \ No newline at end of file