layout | title | inheader | permalink |
---|---|---|---|
page |
Viikko 6 |
false |
/tehtavat6/ |
{% include laskari_info.md part=6 %}
Tehtävät 2-5 liittyvät materiaalin ohjelmistosuunnittelua käsittelevän osan 4 niihin lukuihin, joihin on merkitty [viikko 5] tai [viikko 6].
Tehtävät 2-5 liittyvät materiaalin ohjelmistosuunnittelua käsittelevän osan 4 niihin lukuihin, joihin on merkitty [viikko 5] tai [viikko 6].
Tämän viikon monivalintatehtävät.
{% include typo_instructions.md %}
{% include norppa.md %}
Tehtävät palautetaan GitHubiin, sekä merkitsemällä tehdyt tehtävät palautussovellukseen <{{site.stats_url}}> välilehdelle "my submission".
Katso tarkempi ohje palautusrepositorioita koskien täältä.
Tätä tehtävää ei palauteta mihinkään!
Lue http://git-scm.com/book/en/Git-Branching-Rebasing ja https://www.atlassian.com/git/tutorials/rewriting-history#git-rebase
Aikaansaa seuraavankaltainen tilanne:
------- master
\
\--- haara
"Rebeissaa" haara masteriin, eli aikaansaa seuraava tilanne:
------- master
\
\--- haara
Varmista komennolla gitk --all
että tilanne on haluttu.
"Mergeä" master vielä haaraan:
\ master
\--- haara
Lopputuloksena pitäisi siis olla lineaarinen historia ja master sekä haara samassa. Varmista jälleen komennolla gitk --all
että kaikki on kunnossa.
Poista branch haara. Etsi googlaamalla komento, jolla saat tuhottua branchin.
Kurssirepositorion hakemistosta koodi/viikko6/query-language löytyy jälleen yksi versio tutusta NHL-tilastojen tarkasteluun tarkoitetusta ohjelmasta.
Tällä kertaa olemme kiinnostuneita tekemään hieman monimutkaisempia "kyselyjä" pelaajatietoihin, esim. listaa kaikki joukkueen PHI pelaajat, joilla on vähintään 5 maalia ja vähintään 5 syöttöä.
Koodin onkin luotu hieman valmista kalustoa, josta pääset liikkeelle. Yllä olevan kyselyn voi suorittaa seuraavasti:
def main():
url = "https://nhlstatisticsforohtu.herokuapp.com/players.txt"
reader = PlayerReader(url)
stats = Statistics(reader)
matcher = And(
HasAtLeast(5, "goals"),
HasAtLeast(5, "assists"),
PlaysIn("PHI")
)
for player in stats.matches(matcher):
print(player)
Luokalle Statistics
on tehty metodi matches
, joka palauttaa listan niistä pelaajista, joille parametrina annettun olion metodi matches
palauttaa True
.
Tutustu ohjelman rakenteeseen.
- Huomioi miten
HasAtLeast
-luokan metodimatches
käyttää funktiota getattr saadakseen parametrina annetun attribuutin arvon - Toinen huomioinarvoinen piirre on
And
-luokan konstruktorissa käytetty vaihtuvamittainen parametrilista, jonka tunnista*
-etuliitteestä. Syntaksin avulla*matchers
sisältää listan konstruktorille annetuista argumenteista
Toteuta matches
-metodin toteuttavat luokat, joiden avulla voit tehdä seuraavat operaatiot:
- All (tosi kaikille pelaajille)
- Not (parametrina olevan ehdon negaatio)
- HasFewerThan (HasAtLeast-komennon negaatio eli esim. on vähemmän kuin 10 maalia)
Kaikille pelaajille tosi ehto all ei ole vielä tämän tehtävän kannalta kovin mielenkiintoinen, sitä pystyy kuitenkin hyödyntämään neljännessä tehtävässä.
Voit tarkistaa toteutuksesi toimivuuden tekemällä kyselyn:
matcher = And(
Not(HasAtLeast(1, "goals")),
PlaysIn("NYR")
)
Vastauksena pitäisi olla joukkueen NYR pelaajista ne, joilla ei ole vähintään yhtä maalia, eli 0 maalia tehneet:
Tony DeAngelo NYR 0 + 1 = 1 Tim Gettinger NYR 0 + 0 = 0 Tarmo Reunanen NYR 0 + 1 = 1 Zac Jones NYR 0 + 4 = 4 Justin Richards NYR 0 + 1 = 1 Keith Kinkaid NYR 0 + 0 = 0 Igor Shesterkin NYR 0 + 0 = 0 Alexandar Georgiev NYR 0 + 0 = 0
Kyselyn
matcher = And(
HasFewerThan(1, "goals"),
PlaysIn("NYR")
)
tulisi palauttaa täsmälleen sama lista.
Toteuta matches
-metodin toteuttava luokka Or
, joka on tosi silloin jos ainakin yksi sen parametrina saamista ehdoista on tosi.
Kyselyn
matcher = Or(
HasAtLeast(30, "goals"),
HasAtLeast(50, "assists")
)
tulee palauttaa ne, joilla on vähintään 30 maalia tai 50 syöttöä, eli seuraava lista
Auston Matthews TOR 41 + 25 = 66
Patrick Kane CHI 15 + 51 = 66
Alex DeBrincat CHI 32 + 24 = 56
Mikko Rantanen COL 30 + 36 = 66
Leon Draisaitl EDM 31 + 53 = 84
Connor McDavid EDM 33 + 72 = 105
Kyselyn
matcher = And(
HasAtLeast(40, "points"),
Or(
PlaysIn("NYR"),
PlaysIn("NYI"),
PlaysIn("BOS")
)
)
tulee palauttaa kaikki vähintään 40 pistettä tehneet jotka pelaavat jossain seuraavista joukkueista NYI, NYR tai BOS. Lista näyttää seuraavalta:
Mathew Barzal NYI 17 + 28 = 45
Ryan Strome NYR 14 + 35 = 49
Mika Zibanejad NYR 24 + 26 = 50
Pavel Buchnevich NYR 20 + 28 = 48
Artemi Panarin NYR 17 + 41 = 58
Adam Fox NYR 5 + 42 = 47
Patrice Bergeron BOS 23 + 25 = 48
David Krejci BOS 8 + 36 = 44
Brad Marchand BOS 29 + 40 = 69
David Pastrnak BOS 20 + 28 = 48
Kyselyt perustuvat rakenteeltaan decorator-suunnittelumalliin, vastaavasti kuten materiaalin osan 4 esimerkissä dekoroitu pino. And- ja OR-muotoiset kyseltyt on muodostettu myös erään suunnittelumallin, compositen hengessä, ne ovat Matcher-rajapinnan toteuttavia olioita, jotka sisältävät itse monta Matcher-olioa. Niiden käyttäjä ei kuitenkaan tiedä sisäisestä rakenteesta mitään.
Matcher-olioiden avulla tehtyä kyselykieltä vaivaa se, että kyselyjen rakentaminen on ikävää, sillä jokaista kyselyn osaa kohti on luotava new-komennolla uusi olio.
Tee materiaalin osassa 4 esitellyn pinorakentajan hengessä kyselyrakentaja, jonka avulla voit luoda Matcher-olioita.
Rakentaja voi toimia esim. seuraavaan tapaan.
Ensin kysely, joka palauttaa jokaisen pelaajan:
def main():
url = "https://nhlstatisticsforohtu.herokuapp.com/players.txt"
reader = PlayerReader(url)
stats = Statistics(reader)
query = QueryBuilder()
matcher = query.build()
for player in stats.matches(matcher):
print(player)
Tässä kyselyssä voi ja kannattaa hyödyntää edellisen tehtävän All
-matcheria.
Seuraavaksi kysely, missä tulostetaan pelaajat, joiden joukkue on NYR:
def main():
url = "https://nhlstatisticsforohtu.herokuapp.com/players.txt"
reader = PlayerReader(url)
stats = Statistics(reader)
query = QueryBuilder()
matcher = query.playsIn("NYR").build()
for player in stats.matches(matcher):
print(player)
Seuraavaksi kysely, missä tulostetaan pelaajat joiden joukkue on NYR, joilla on vähintään 5 ja vähemmän kuin 10 maalia:
def main():
url = "https://nhlstatisticsforohtu.herokuapp.com/players.txt"
reader = PlayerReader(url)
stats = Statistics(reader)
query = QueryBuilder()
matcher = query.playsIn("NYR").hasAtLeast(5, "goals").hasFewerThan(10, "goals") .build()
for player in stats.matches(matcher):
print(player)
Pelaajien lista on seuraava:
Brendan Smith NYR 5 + 5 = 10
Kevin Rooney NYR 8 + 6 = 14
Adam Fox NYR 5 + 42 = 47
Filip Chytil NYR 8 + 14 = 22
K'Andre Miller NYR 5 + 7 = 12
Kaapo Kakko NYR 9 + 8 = 17
Peräkkäin ketjutetut ehdot siis toimivat "and"-periaatteella.
Tässä tehtävässä riittää, että kyselyrakentaja osaa muodostaa and-periaatteella yhdistettyjä ehtoja.
Pitkät metodikutsuketjut, esim.
matcher = query.playsIn("NYR").hasAtLeast(5, "goals").hasFewerThan(10, "goals") .build()
ovat luettavuudeltaan hieman ikäviä, jos ne kirjoitetaan monelle riville. Usein ne onkin tapana jakaa "kutsu per rivi"-periaatteella:
matcher = (
query
.playsIn("NYR")
.hasAtLeast(5, "goals")
.hasFewerThan(10, "goals")
.build()
)
Python ikävä kyllä edellyttää tässä "ylimääräisten" sulkujen käyttöä.
Laajennetaan kyselyrakentajaa siten, että sen avulla voi muodostaa myös or-ehdolla muodostettuja kyselyjä. Or-ehdon sisältävä kysely voi olla muodostettu esim. seuraavasti:
m1 = (
query
.playsIn("PHI")
.hasAtLeast(10, "assists")
.hasFewerThan(5, "goals")
.build()
)
m2 = (
query
.playsIn("EDM")
.hasAtLeast(40, "points")
.build()
)
matcher = query.oneOf(m1, m2).build()
Pelaajalistan tulisi olla:
Travis Sanheim PHI 3 + 12 = 15
Philippe Myers PHI 1 + 10 = 11
Tyson Barrie EDM 8 + 40 = 48
Leon Draisaitl EDM 31 + 53 = 84
Connor McDavid EDM 33 + 72 = 105
Tai sama ilman apumuuttujia:
matcher = (
query
.oneOf(
query.playsIn("PHI")
.hasAtLeast(10, "assists")
.hasFewerThan(5, "goals")
.build(),
query.playsIn("EDM")
.hasAtLeast(40, "points")
.build()
)
.build()
)
On mahdollista ja jopa todennäköistä, että ensimmäinen ratkaisusi ei toimi jos apumuuttujia ei käytetä. Mieti tarkkaan missä vika ja yritä korjata tilanne. Vaadittava muutos ei ole iso.
Isoa projektia on vaikea ylläpitää yksin ja vielä vaikeampaa on löytää oikeat ratkaisut jokaiseen ongelmaan, kun ohjelmisto kasvaa. On vaikeaa hallita itse kaikkea ja jotkin osa-alueet eivät välttämättä edes miellytä jolloin niihin on vaikea paneutua. Saatat löytää itsesi ajattelemasta vaikkapa: "Lukisipa joku tietorakenteiden asiantuntija tämän osuuden läpi ja tsekkaisi, että HashSet on nyt varmasti se tehokkain ratkaisu...".
Ehkäpä et edes ajatellut asiaa, mutta joku silti näyttää, että binäärihakupuu onkin tilanteessa tehokkaampi ratkaisu, koodaa korjaukset puolestasi lähdekoodiin sekä tekee muutoksista pull requestin. Onneksi julkaisit projektisi Open Sourcena!
GitHub on täynnä Open Source -projekteja, jotka kaipaavat panostasi. Mikäs sen kivempaa, kuin käyttää muutama tunti suosikkirepositioriosi lähdekoodin parissa ja korvata sieltä huomaamasi epäelegantti ratkaisu paremmalla. Useilla repositorioilla on valmiit ohjeet muutosehdotusten tekemiseen repositorion juuresta löytyvässä tiedostossa Contributing.md. Tässä esimerkiksi bluebird.js:än CONTRIBUTING.md.
Tehtävänäsi on harjoitella muutosehdotuksen tekemistä "open source -projektiin" sekä vieraan koodin lukemista ja refaktorointia.
- Valitse yksi repositorio miniprojektien joukosta
- Mielellään sellaisen ryhmän repositorio, jolla ei ole jo viittä pull requestia.
- Ja luonnollisesti sellainen, jonka koodiin haluat tehdä jotain muutoksia
- Forkkaa repositorio
- Tee forkattuun repositorioon uusi branch nimellä "muutoksia"
- Tee luomaasi branchiin "tyhjä" pull request: lisää esimerkiksi yksi tyhjä rivi README.md:hen, pushaa uusi branch GitHubiin ja tee branchista pull request.
- Tyhjän pull requestin tarkoituksena on varata sinulle paikka kyseisen repositorion muutoksentekijöiden joukosta. Haluamme, että kaikki ryhmät saavat suunilleen tasaisesti pull requesteja, eli jos repositoriossa on niitä jo runsaasti, etsi mielellään jokin muu repositorio.
- Etsi ryhmän lähdekoodista jotain refaktoroitavaa
- Kyseessä ei tarvitse olla iso muutos, esimerkiksi muuttujan/metodin uudelleennimeäminenkin riittää
- Refaktoroi ja committaa
- Käy katsomassa tekemääsi tyhjää pull requestia. Mitä tapahtui?
- Rebeissaa (ks. tämän viikon ensimmäinen tehtävä) luomasi branch paikalliseen master branchin päälle. Pushaa. Tapahtuiko pull requestissa muutoksia?
- Otsikoi tekemäsi pull request niin, että se kuvaa tekemiäsi muutoksia. Tarkenna otsikon alle mitä teit ja miksi.
- Jos ryhmä pyytää sinua tekemään muutoksia pull requestiisi, tee halutessasi tarvittavat muutokset ja committaa. Päivittyikö pull request?
- Kun ryhmä on hyväksynyt muutoksesi, voit poistaa luomasi branchin
Laita palautusrepositorioosi tiedosto PULL.md ja sen sisällöksi linkki pull requestiin.
{% include submission_instructions.md %}