Naloga: Nepremičnina

Naloga: Nepremičnina

Avtor: Andrej Pavšič

Besedilo naloge

Napiši razred Nepremicnina , kjer hranimo podatke o nepremičninah. Podatke, ki jih potrebujemo so:

a) številka parcele; širina parcele (v metrih); dolžina parcele (v metrih); cona, v kateri se parcela nahaja (zazidljiva ali ne); občina, v kateri se nahaja; cena

Poleg tega potrebujemo še konstruktorja (privzete vrednosti so širina 20m, dolžina 25m, cona je zazidljiva, občina je Ljubljana in cena je 250.000 €) Seveda pa naš razred pozna še vsaj naslednje metode:
b) Metode, ki vrnejo številko, širino, dolžino, občino in ceno parcele.
c) Metoda, ki vrne true, če je parcela zazidljiva in false če ni.
d) Metoda, ki spremeni podatke o številki, dolžini, širini, coni in ceni parcele (občine pa seveda ne moremo spremeniti)
e) Metodo, ki nam izračuna velikost parcele.

Pri tem pa seveda pazimo, da so podatki, ki jih vnašamo smiselni. Rešite naslednje probleme:
f) Izpišite najdražjo zazidljivo parcelo.
g) Za vsako občino izpišite najdražjo in najcenejšo parcelo.
h) Zaradi recesije so se cene vseh zazidljivih parcel znižale za n, nezazidljivih pa za m%. Popravi podatke o cenah parcel, ki so na datoteki.
i) Zgodila se je menjava občinske oblasti in občina Kranj se je preimenovala v Carnium. Popravi ustrezne zapise na datoteki.
j) Dana je tabela nepremičnin. Iz tabele izloči vse tiste, katerih cena je "nenormalno nizka ali visoka". Cena je nenormalno nizka, če se za več kot 15% razlikuje od povprečne cene v ustrezni coni (torej zazdiljive posebej in nezazidljive posebej).
k) Vsaj en (zaželeno pa več) problem po vaši izbiri ... (opišite jih!):

  • Povprečna cena za kvadratni meter zazidljive parcele v Ljubljani znaša 333 €. Izračunaj standardni odklon cen zazidljivih parcel v Ljubljani.

Opis problema in ideja rešitve

a) Sestavili bomo razred Nepremicnina , ki bo v konstruktorju hranil podatke o številki, širini, dolžini in ceni parcele, ime občine kjer se parcela nahaja ter podatek o zazidljivosti parcele.

b) Za vsak podatek sestavimo t.i. "get metodo", ki nam vrne vrednost podatka.

d) Spisati bomo morali tudi t.i. "set metode", s katerimi bomo lahko spreminjali podatke za številko, širino, dolžino, cono in ceno parcele. Občine pa parceli ne moremo spremeniti, zato za podatek o občini ni potrebno sestaviti set metode.

e) Velikost parcele bomo izračunali kot produkt širine in dolžine parcele.



Nadaljnje metode ne bodo objektne, zato se s kurzorjem pomaknemo nazaj do levega roba.

f) Najdražjo zazidljivo parcelo bomo dobili, če bomo z zanko for šli po seznamu ustvarjenih objektov razreda Nepremicnina, kjer bomo med seboj preverjali ceno tistih parcel, ki so zazidljive (ko bo vrednost self.cona enaka logični vrednosti True ).

g) Pri iskanju najcenejše in najdražje parcele iz vsake občine si bomo pomagali s slovarji, kjer bo ključ slovarja ime občine, vrednost pa dvojica, ki bo vsebovala podatek o številki in ceni parcele.

h) V primeru recesije s pomočjo set metode zmanjšamo ceno nepremičnini, pri čemer moramo ločiti zazidljive od nezazidljivih.

i) Da bi vsem parcelam, ki se nahajajo v občini Kranj, preimenovali občino v Carnium, moramo najprej v razredu Nepremicnina ustvariti metodo, ki ime občine kranj spremeni v carnium . Nato pa izven razreda definiramo metodo, ki s for zanko pregleda seznam objektov razreda Nepremicnina in vse pojavitve 'kranj' med občinami spremeni s 'carnium' .

j) S for zanko po seznamu, kjer so shranjeni objekti razreda Nepremicnina , najprej v dva seznama ločimo zazidljive od nezazidljivih parcel. Hkrati še v dva seznama dodajamo cene parcel - zazidljive v en in nezazidljive v drug seznam. Če je seznam zazidljivih oz. nezazidljivih parcel neprazen, potem iz drugega seznama izračunamo povprečno ceno zazidljive oz. nezazidljive parcele. Nato samo še primerjamo cene parcel s povprečno ceno parcele po formuli: "0.85*povprečna<cenaParcele<1.15*povprečna". Če je cena parcele v okviru teh mej, potem je parcela normalna in jo dodamo na seznam normalnih.

k) Najprej iz seznama parcel izločimo tiste, ki se nahajajo v Ljubljani in so zazidljive in jih shranimo v nek nov seznam. Nato pri vsaki parceli v tem novem seznamu izračunamo produkt površine s povprečno vrednostjo parcele na kvadratni meter, ga odštejemo od dejanske cene parcele in kvadriramo. Te vrednosti seštejemo in na koncu izračunamo koren te vsote s številom zazidljivih parcel v Ljubljani. Tako dobimo standardni odklon zazidljivih parcel v Ljubljani.

Razlaga algoritma

a) Ustvarimo razred Nepremicnina . V razredu definiramo konstruktor, ki sprejme podatke o številki, širini, dolžini, coni (zazidljiva/ nezazidljiva), občini in ceni parcele. Številko, širino, dolžino in ceno vnašamo kot števila (6. vrstica) s pozitivnimi vrednostmi (9. vrstica), cono kot logično vrednost True ali False (7.vrstica), občino pa kot niz (8. vrstica).

b) Za vsak podatek, ki ga hranimo v konstruktorju sestavimo t.i. "get metodo", ki nam vrne vrednost le tega (18. do 29. vrstica).

d) Za številko, širino, dolžino, ceno in ceno sestavimo t.i. "set metode", s katerimi lahko spreminjamo želene podatke parcele (32. do 45. vrstica). Za občino takšne metode ne ustvarimo!

e) Velikost parcele izračunamo kot produkt širine in dolžine (47. vrstica). "Get metode", "set metode" in metoda velikost parcele so objektne!

Opisi nadaljnjih metod niso metode razreda Nepremicnina !

f) Najdražjo zazidljivo parcelo definiramo kot metodo izven razreda Nepremicnina , kjer za parameter dobimo seznam objektov tega razreda. V 56. vrstici ustvarimo prazen seznam, kjer bomo hranili podatke o najdražji parceli ter spremenljivko cena z vrednostjo 0, in jo bomo zamenjali, kadar bomo našli kakšno dražjo parcelo v seznamu sez . Po seznamu sez spustimo for zanko. V primeru, da je vrednost cone tekočega objekta True (cona je zazidljiva), primerjamo ceno parcele s spremenljivko cena. Če sta si ceni enaki (59. vrstica), potem na seznam najdražjih dodamo dvojico (številka parcele, občina), če pa je cena parcele večja od trenutno največje cene (62. vrstica), ki jo hranimo v spremenljivki cena, potem seznamu najdražjih "izbrišemo" stare dvojice in vanj shranimo dvojico (številka parcele, občina). Ko se zanka izteče, samo še vrnemo seznam.

g) Najdražjo in najcenejšo parcelo po občinah bomo našli s pomočjo slovarjev. Slovarje pa bomo uporabili, ker imajo to lepo lastnost, da preslikajo množico ključev v množico vrednosti. Če bomo torej imeli več parcel iz iste občine, bomo v slovarju imeli samo eno parcelo iz te občine, le vrednosti bomo spreminjali (glede na določene kriterije). Ustvarimo dva slovarja, prvega poimenujemo najdrazja , drugega pa najcenejsa . Metoda najPoObcinah za parameter sprejme seznam objektov iz razreda Nepremicnina . Po temu seznamu spustimo for zanko (73. vrstica). Ker bomo v ključih slovarja hranili imena občin, najprej preverimo, če je občina že v katerem od slovarjev (75. in 77. vrstica). Če ni, potem v slovar dodamo ključ z vrednostma kot občina: [številka parcele, cena] . Če pa se katera izmed občin že nahaja v katerem od slovarjev, preverimo ceno parcele s ceno, ki je hranjena v vrednosti ključa. Če ima parcela iz občine, višjo ceno kot občina iz slovarja najdrazja , potem ključu, ki hrani ime te občine, zamenjamo vrednosti [številka parcele, občina] (82. vrstica). Podobno naredimo v seznamu najcenejsa (84. vrstica). Na koncu samo izpišemo stavke, katera je najdražja oz. najcenejša parcela v kateri občini in zraven podamo še ceno te parcele. To naredimo z while zanko po obeh slovarjih.

h) Pri metodi recesija bomo zazidljivim parcelam zmanjšali vrednost za n procentov ter nezazidljivim parcelam za m procentov. Tudi tukaj bomo za parameter prejeli seznam objektov razreda Nepremicnina , zraven pa bosta še parametra n in m . Spustimo zanko po seznamu nepremičnin. Če je parcela zazidljiva, ji spremenimo vrednost z objektno metodo setCena() , kjer od cene odštejemo m procentov cene. Če je parcela nezazidljiva, ji spremenimo vrednost z objektno metodo setCena() , kjer od cene odštejemo n procentov cene.

i) Če hočemo spremeniti ime občine, moramo skočiti nazaj v razred Nepremicnina in v njem definirati novo metodo (45. vrstica). Ta v primeru, da se parcela nahaja v Kranju, spremeni lastnost občine 'kranj' v 'carnium' . Sedaj imamo metodo, ki bo spremenila ime občine, zato s to metodo samo še pregledamo seznam objektov s for zanko (110. do 113. vrstica).

j) Pri metodi normalne(sez) , kjer je parameter sez seznam objektov razreda Nepremicnina , ustvarimo dva prazna seznama, kjer bomo ločili zazidljive parcele od nezazidljivih (118. vrstica) in dva seznama kamor bomo dodajali cene parcel, zazidljivih v enega in nezazidljivih v drugega. S for zanko po elementih seznama sez preverimo, katere parcele so zazidljive in katere nezazidljive. Objekte, kjer je vrednost cone True (122. vrstica)strpamo v seznam zazidljivih ter cene, ki so hranjene v takih objektih dodamo v seznam ceneZaz . Objekte, kjer je vrednost cone False (125. vrstica) pa strpamo v seznam nezazidljivih parcel ter cene, ki so hranjene v takih objektih dodamo v seznam ceneNezaz . Seznam zazidljivih oz. nezazidljivih bo nadaljnje za nas zanimiv samo, če bo neničeln (129. in 134. vrstica). V takem primeru izračunamo povprečno vrednost parcele (zazidljive posebej in nezazidljive posebej) količnik med vsoto cen seznama, kjer smo hranili cene z dolžino tega seznama. Po vsakem seznamu (zazidljivih, nezazidljivih) spustimo zanko for in primerjamo ceno tekočega objekta s povprečno ceno. Če je cena parcele v meji med 85% in 115% povprečne cene (132. in 135. vrstica), potem je parcela normalna in jo dodamo na seznam (normalne zazidljive posebej, normalne nezazidljive posebej). Na koncu vrnemo seznam normalnih zazidljivih in normalnih nezazidljivih parcel.

k)Z metodo stdOdlkonLj(sez) bomo preverjali standardni odklon cen zazidljivih parcel v občini Ljubljani. V tej metodi bomo najprej v en seznam strpali vse parcele, ki se nahajajo v Ljubljani in so zazidljive (146. vrstica). Standardni odklon je definiran kot:

Povprečna cena parcele je odvisna od površine parcele in jo bomo dobili kot produkt kvadrature parcele s povprečno vrednostjo kvadratnega metra zazidljive parcele v Ljubljani. Števec ulomka pod korenom bodo dobili s pomočjo for zanke. Pred zanko nastavimo spremenljivko, kateri bomo prištevali kvadrat razlike cene parcele s povprečno vrednostjo parcele, na 0. V zanki najprej izračunamo povprečno vrednost parcele (149. vrstica) in v naslednji vrstici spremenljivki vs prištejemo kvadrat razlike med ceno parcele tekočega objekta in povprečno vrednostjo za parcelo s takšno kvadraturo. Na koncu vnemo koren količnika spremenljivke vs s številom zazidljivih parcel v Ljubljani.

Koda v Pythonu

from types import *

class Nepremicnina:
    
stevilka parcele, sirina, dolzina, zazidljiva (True/False), obcina, cena
    def __init__(self, stevilka, sirina=20, dolzina=25, cona=True, obcina='ljubljana', cena=250000):
        assert (type(stevilka) and type(sirina) and type(dolzina) and type(cena))==int, 'Številka, širina, dolžina in cena parcele morajo biti podana kot število'
        assert type(cona)==bool, 'Vnesite True, če je parcela zazidljiva oz. False če je parcela nezazidljiva.'
        assert type(obcina)==str, 'Ime občine je potrebno vnesti kot niz!'
        assert (stevilka and sirina and dolzina and cena)>0, 'Številka, širina, dolžina in cena parcele morajo biti nenegativna števila!'
        self.st=stevilka
        self.sirina=sirina
        self.dolzina=dolzina
        self.cona=cona
        self.obcina=obcina.lower()
        self.cena=cena
# =====================

    def getStevilka(self):
        return self.st
    def getSirina(self):
        return self.sirina
    def getDolzina(self):
        return self.dolzina
    def getObcina(self):
        return self.obcina
    def getCena(self):
        return self.cena
    def getCona(self):
        return self.cona
# =====================

    def setStevilka(self,novaSt):
        assert type(novaSt)==int and novaSt>0, 'Nova številka mora biti pozitivno celo število!'
        self.st=novaSt
    def setSirina(self,novaSirina):
        assert type(novaSirina)==int and novaSirina>0, 'Nova širina mora biti pozitivno celo število!'
        self.sirina=novaSirina
    def setDolzina(self,novaDolzina):
        assert type(novaDolzina)==int and novaDolzina>0, 'Nova dolžina mora biti pozitivno celo število!'
        self.dolzina=novaDolzina
    def setCena(self,novaCena):
        assert type(novaCena)==int and novaCena>0, 'Nova cena mora biti pozitivno celo število!'
        self.cena=novaCena
    def setCona(self):
        if self.cona==True: self.cona=False
        else: self.cona=True
# =====================
    def velikostParcele(self): # Izračunamo kvadraturo parcele.
        return self.sirina*self.dolzina
# =====================
    def krToCar(self): # Preimenovanje obbčine kranj v carnium.
        if self.obcina== 'kranj': self.obcina='carnium'

# ===========================================================================
def najdrazjaZazidljivaParcela(sez=[]):
    
v seznam sez vnesemo objekte razreda Nepremicnina
    najdrazja=[];cena=0
    for i in sez:
        if i.getCona()==True: # v primeru da je parcela zazidljiva
            if i.getCena()==cena: # če imamo več zazidljivih parcel z najvišjo ceno, vrnemo vse
                najdrazja.append(i.getStevilka(),i.getObcina())

            if i.getCena()>cena:
                najdrazja=(i.getStevilka(),i.getObcina())
                cena=i.getCena()

    return najdrazja

# ===========================================================================
najdrazja={}
najcenejsa={}
def najPoObcinah(sez=[]):
    
v seznam sez vnesemo objekte razreda Nepremicnina
    for i in sez:
        # če občine še ni v slovarju najdražjih oz. najcenejšh
        if i.getObcina() not in najdrazja:
            najdrazja[i.getObcina()]=[i.getStevilka(),i.getCena()] # shranimo v slovar kot {obcina:[stevilka,cena]}
        if i.getObcina() not in najcenejsa:
            najcenejsa[i.getObcina()]=[i.getStevilka(),i.getCena()]

        # če je v slovarju že kakšna parcela iz iste občine, potem primerjamo cene
        if i.getObcina() in najdrazja:
            if i.getCena()>najdrazja.get(a.getObcina())[1]: najdrazja[i.getObcina()]=[i.getStevilka(),i.getCena()] # če ima višjo ceno
        if i.getObcina() in najcenejsa:
            if i.getCena()<najdrazja.get(a.getObcina())[1]: najcenejsa[i.getObcina()]=[i.getStevilka(),i.getCena()] # če ima nižjo ceno

    # imamo slovarja najdražjih in najcenejših parcel v različnih občinah
    # najprej izpišemo najdražje, nato naredimo presledek in izpišemo še najcenejše
    # če imamo za neko občino podano samo eno parcelo, potem jo izpiše med najdražjimi in najcenejšimi
    k=0
    while k<len(najdrazja):
        obcina=list(najdrazja.keys())[k]; parcela=list(najdrazja.values())[k][0];cena=list(najdrazja.values())[k][1]
        print('Najdražja parcela v občini '+obcina.capitalize()+' je parcela {0}, ki stane {1} €.'.format(parcela,cena))
        k+=1

    print('\n')
    k=0
    while k<len(najcenejsa):
        obcina=list(najcenejsa.keys())[k]; parcela=list(najcenejsa.values())[k][0];cena=list(najcenejsa.values())[k][1]
        print('Najcenejša parcela v občini '+obcina.capitalize()+' je parcela {0}, ki stane {1} €.'.format(parcela,cena))
        k+=1

# ===========================================================================
def recesija(sez=[],n=0,m=0):
    
v seznam sez vnesemo objekte razreda Nepremicnina
    for i in sez:
        if i.getCona()==True: i.setCena(int(i.getCena()-(n/100)*i.getCena())) # Zazidljivim parcelam znižamo ceno za n procentov.
        if i.getCona()==False: i.setCena(int(i.getCena()-(m/100)*i.getCena())) # Nezazidljivim parcelam znižamo ceno za m procentov.

# ===========================================================================
def carnium(sez=[]):
    
v seznam sez vnesemo objekte razreda Nepremicnina
    for i in sez:
        i.krToCar() # Če je v seznamu kakšna parcela iz ob občine Kranj, ime občine preimenujemo v carnium.

# ===========================================================================

def normalne(sez=[]):
    zazidljive=[];nezazidljive=[]
    ceneZaz=[];ceneNezaz=[]

    for i in sez:
        if i.getCona()==True: # zazidljive
            zazidljive.append(i)
            ceneZaz.append(i.getCena())
        else:
            nezazidljive.append(i) # nezazidljive
            ceneNezaz.append(i.getCena())

    if len(zazidljive)!=0:povZaz=sum(ceneZaz)/len(ceneZaz) # če seznam zazidljivih ni prazen, izračunamo povprečno ceno zazidljive parcele
    normalneZaz=[]
    for k in zazidljive:
        if 0.85*povZaz <k.getCena() <1.15*povZaz: normalneZaz.append(k) # če se za več kot 15% ne razlikuje od povprečne cene, je normalna

    if len(nezazidljive)!=0: povNezaz=sum(ceneNezaz)/len(ceneNezaz) # če seznam nezazidljivih ni prazen, izračunamo povprečno ceno nezazidljive parcele
    normalneNezaz=[]
    for l in nezazidljive:
        if 0.85*povNezaz <l.getCena() <1.15*povNezaz: normalneNezaz.append(l) # če se za več kot 15% ne razlikuje od povprečne cene, je normalna

    return normalneZaz, normalneNezaz
# ===========================================================================
from math import *
def stdOdklonLj(sez=[]):
    
v seznam sez vnesemo objekte razreda Nepremicnina
    lj=[]
    for i in sez:
        if i.getObcina()=='ljubljana' and i.getCona()==True: lj.append(i) # v seznam lj shranimo objekte oz. nepremičnine, ki se nahajajo v ljubljani in so zazidljive
    vs=0
    for k in lj:
        povCena=k.velikostParcele()*333; # povprečna vrednost kvadratnega metra v ljubljani znaša 333 €
        vs+=(k.getCena()-povCena)**2 # kvadrat razlike med ceno parcele in povprečno ceno parcele
    return sqrt(vs/len(lj)) # po formuli za standardni odklon

Testni primeri

Metode bom testiral tako, da bom sestavil par objektov razreda Nepremicnina in na njih preizkusil spisane ukaze. a=Nepremicnina(1, 20,25,True,'ljubljana',200000)
b=Nepremicnina(2, 30,25,True,'ljubljana',210000)
c=Nepremicnina(3, 40,100,False,'ljubljana',200000)
d=Nepremicnina(1, 50,50,False,'kranj', 80000)
e=Nepremicnina(3, 20,20,True,'kranj',150000)

f=Nepremicnina(10, 20,15,True,'ljubljana',100000)
g=Nepremicnina(100, 30,30,True,'ljubljana',200000)
h=Nepremicnina(1, 20,25,True,'ljubljana',200000)

Vir

0%
0%