4η Εργαστηριακή άσκηση. Λύσεις.

Πρόβλημα 1: Γράψτε μία συνάρτηση με όνομα uniqueList η οποία θα δέχεται μία λίστα L και θα επιστρέφει μία άλλη λίστα M η οποία θα περιέχει τα μοναδικά στοιχεία της L (δηλαδή, θα περιέχει μόνο μία φορά κάθε στοιχείο που περιέχεται στην L). Για παράδειγμα, αν δώσουμε τη λίστα L=[1,2,3,3,5,5,6,7,3] πρέπει να πάρουμε την M=[1,2,3,5,6,7].

Απάντηση: Η ιδέα είναι απλή και την έχουμε δει άλλη μια φορά στο 8ο φυλλάδιο προβλημάτων. Προτού προσθέσουμε κάτι στη λίστα M ελέγχουμε αν είναι ήδη στοιχείο της. Δείτε τον κώδικα του uniqueList.py.


def uniqueList(L):
    M = []
    for item in L:
        if item not in M: M.append(item)
    return M

# Let us try our code

L = [1,2,3,3,5,5,6,7,3]
M = uniqueList(L)
print('Initial list:', L)
print('Unique elements:', M)

Πρόβλημα 2: Γράψτε μία πραγματική συνάρτηση f(x) όπου x ένας πραγματικός αριθμός. Γράψτε επίσης μία συνάρτηση points η οποία δέχεται δύο πραγματικούς αριθμούς a, b και έναν ακέραιο n και κατασκευάζει μία λίστα η οποία περιέχει n ισαπέχοντα σημεία $x_i$ με $x_0 = a$ και $x_n = b$. Επίσης, κατασκευάζει μία ακόμα λίστα με τις τιμές $f(x_i)$. Γράψτε ένα πρόγραμμα το οποίο θα τυπώνει τις δύο αυτές λίστες. Για παράδειγμα, χρησιμοποιήστε $f(x)=x^3-16x$ στο διάστημα $[-5,5]$.

Απάντηση: Κατασκευάζουμε τις δύο λίστες και τις επιστερέφουμε από τη συνάρτησης points. To κύριο μέρος του προγράμματος απλά ορίζει το διάστημα $[a, b]$ και τον αριθμό των σημείων. Δείτε τον κώδικα του points.py.


def f(x):
    return x**3 - 16*x

def points(a, b, n):
    dx = (b - a) / n
    x = []
    y = []

    for i in range(n+1):
        p = a + i*dx
        x.append( p )
        y.append( f(p) )

    return (x, y)

# Let us try our code

a = -5; b = 5; n = 8
x, y = points(a, b, n)

print('x   :', x)
print('f(x):', y)

Πρόβλημα 3: Γράψτε μία συνάρτηση str2List η οποία θα δέχεται μία συμβολοσειρά και θα επιστρέφει μία λίστα με στοιχεία χαρακτήρες οι οποίοι θα είναι τα μοναδικά γράμματα τα οποία περιέχονται στη συμβολοσειρά. Για παράδειγμα, αν η συμβολοσειρά είναι 'Maria!' η συνάρτηση θα πρέπει να επιστρέφει τη λίστα ['m','a','r','i'].

Απάντηση: Χρησιμοποιούμε την ιδέα του πρώτου προβλήματος για να βρούμε τους χαρακτήρες που εμφανίζονται μία μόνο φορά. Δείτε τον κώδικα του str2List.py. Σημειώνουμε ακόμα, ότι η επιλογή των γραμμάτων από την ακολουθία χαρακτήρων μπορεί να γίνει με τη μέθοδο isalpha(), αντικαθιστώντας, δηλαδή, την εντολή ελέγχου if x not in letters: continue με το απλούστερο if not x.isalpha(): continue.


def str2List(s):
    letters = 'abcdefghijklmnopqrstuvwxyz'
    L = []

    for x in s:
        if x not in letters: continue
        if x not in L: L.append(x)

    return L

# Let us try our code

s = 'mathematics'
print('Unique letters in', s, str2List(s))

Πρόβλημα 4: Γράψτε μία συνάρτηση με το όνομα funcList η οποία θα βρίσκει τις τιμές συνάρτησης $f(x)$ για όλα τα στοιχεία μίας λίστας (η οποία θα περιέχει πραγματικούς αριθμούς). Η συνάρτηση θα δέχεται μία λίστα και θα επιστρέφει μία νέα λίστα. Θα χρησιμοποιεί μία άλλη συνάρτηση f (την οποία επίσης πρέπει να γράψετε). Για παράδειγμα, αν η αρχική λίστα είναι L=[0.1,0.2,0.3,0.4,0.5] και \( f(x) = sin(x) \), η funcList θα πρέπει να επιστρέφει τη λίστα [0.09983341664682815, 0.19866933079506122, 0.29552020666133955, 0.3894183423086505, 0.479425538604203].

Απάντηση: Το πρόβλημα είναι παρόμοιο με το πρόβλημα 2. Δείτε τον κώδικα του funcList.py.


def f(x):
    return math.sin(x)

def funcList(xlist):
    y = []
    for x in xlist:
        y.append( f(x) )
    return y

# Let us try our code

x = [0.12, -1.3, 2.88, -6.7, 3.5]
y = funcList(x)

print('x   :', x)
print('f(x):', y)

Πρόβλημα 5: Γράψτε μία συνάρτηση με το όνομα contractList η οποία θα βρίσκει το άθροισμα και το γινόμενο των στοιχείων μίας λίστας. Η συνάρτηση θα δέχεται μία λίστα και θα επιστρέφει δύο πραγματικούς αριθμούς. Για παράδειγμα, αν η αρχική λίστα είναι L=[1,2.5,3,4,5.5,6], η συνάρτηση θα πρέπει να επιστρέφει τους αριθμούς 22.0, 990.0.

Απάντηση: Το πρόβλημα είναι αρκετά εύκολο. Δείτε τον κώδικα του contractList.py.


def contractList(L):
    summ, prod = 0, 1
    for x in L:
        summ += x
        prod *= x
    return (summ, prod)

# Let us try our code

L = [2, 4, 7, 15, 12, 3, 11]

summ, prod = contractList(L)

print('List of elements:', L)
print('Sum of elements:', summ)
print('Product of elements:', prod)

Πρόβλημα 6: Γράψτε μία συνάρτηση values2sign η οποία δέχεται μία λίστα με στοιχεία πραγματικούς αριθμούς και κατασκευάζει μία σειρά χαρακτήρων ως εξής: αν δύο διαδοχικοί αριθμοί είναι θετικοί τότε θέτει τον χαρακτήρα '+', αν είναι αρνητικοί το θέτει '-' και αν δύο διαδοχικοί χαρακτήρες είναι ετερόσημοι τότε θέτει τον χαρακτήρα 'ο'. Για παράδειγμα για τη λίστα [3.1,2,1.2,-1,-2] παίρνουμε την συμβολοσειρά '++ο-'. Στη συνέχεια, γράψτε ένα πρόγραμμα το οποίο ζητάει από το χρήστη πραγματικούς αριθμούς και τους καταχωρεί σε μία λίστα, μέχρι να εμφανιστεί ο αριθμός -1. Βρείτε την αντίστοιχη συμβολοσειρά με χρήση της παραπάνω συνάρτησης (το -1 δεν θα συμπεριλαμβάνεται στον υπολογισμό).

Απάντηση: Το μόνο σημείο στο οποίο κάποια προσοχή είναι η επιλογή των αριθμών από τη λίστα. Μπρούμε είτε να διατρέξουμε τη λίστα με βήμα δύο είτε να "θυμόμαστε" το προηγούμενο στοιχείο της, όπως στην υλοποίηση που παρουσιάζεται παρακάτω. Δείτε τον κώδικα του values2sign.py.


def values2sign(L):
    s = ''
    l = L[0]
    for e in L[1:]:
        if l > 0 and e > 0:
            s += '+'
        elif l < 0 and e < 0:
            s += '-'
        else:
            s += 'o'
        l = e
    return s

# Let's try our code

L = []

while 1:
    x = float(input('Enter a real number: '))
    if x == -1: break
    L.append(x)

print('List of numbers:', L)
print('List of signs:', values2sign(L))

Πρόβλημα 7: Γράψτε μία συνάρτηση distInt η οποία δέχεται μία λίστα με στοιχεία ακεραίους και υπολογίζει τις αποστάσεις μεταξύ διαδοχικών στοιχείων. Η συνάρτηση πρέπει να επιστρέφει τα αποτελέσματα σε μία λίστα. Στη συνέχεια, γράψτε ένα πρόγραμμα το οποίο ζητάει από το χρήστη ακέραιους αριθμούς και τους καταχωρεί σε μία λίστα, μέχρι να εμφανιστεί ο αριθμός -1. Βρείτε τις αποστάσεις μεταξύ των ακεραίων με χρήση της παραπάνω συνάρτησης (το -1 δεν θα συμπεριλαμβάνεται στον υπολογισμό).

Απάντηση: Διατρέχουμε τα στοιχεία της λίστας όπως και στο προηγούμενο πρόβλημα. Δείτε τον κώδικα του distInt.py.


def distInt(L):
    dL = []
    p = L[0]
    for x in L[1:]:
        dL.append( abs(x - p) )
        p = x
    return dL

# Let's try our code

L = []

while 1:
    x = float(input('Enter a real number: '))
    if x == -1: break
    L.append(x)

print('List of numbers:', L)
print('List of distances:', distInt(L))

Πρόβλημα 8: Αν r και s είναι δύο ακολουθίες χαρακτήρων ορίζουμε την απόστασή τους d ως τον αριθμό των θέσεων στις οποίες οι δύο ακολουθίες χαρακτήρων διαφέρουν. Για παράδειγμα, η απόσταση των 'cat' και 'bit' είναι 2 αλλά η απόσταση των 'desks' και 'pen' είναι 4. Γράψτε μια συνάρτηση distStr η οποία με όρισμα δύο ακολουθίες χαρακτήρων υπολογίζει και επιστρέφει την απόστασή τους.

Απάντηση: Πρέπει να σκεφτούμε ότι οι δύο ακολουθίες χαρακτήρων μπορεί να μην έχουν το ίδιο μήκος. Έτσι, συγκρίνουμε τους χαρκτήρες στις θέσεις 0 έως και min(len(r), len(s)) - 1 και στη συνέχει προσθέτουμε στην απόσταση τον ακέραιο max(len(r), len(s)) - min(len(r) - len(s)) (σκεφτείτε το λίγο). Δείτε τον κώδικα του distStr.py.


def distStr(r, s):
    m = min(len(r),len(s))
    M = max(len(r),len(s))
    dist = 0
    for i in range(m):
        if r[i] != s[i]: dist += 1
    return dist + M - m

# Let's try our code

r = 'algebra'
s = 'analysis'

print('Distance between', r, 'and', s + ':', distStr(r,s))

Πρόβλημα 9: Η ακολουθία χαρακτήρων s αποτελείται από μονοψήφιους αριθμούς και τα σύμβολα της πρόσθεσης ή της αφαίρεσης '+', '-'. Για παράδειγμα, η ακολουθία χαρακτήρων s θα μπορούσε να είναι η '3-7+6-1+8'. Γράψτε μια συνάρτηση strArithmetic η οποία δέχεται ως όρισμα μια τέτοια ακολουθία χαρακτήρων, εκτελεί τις πράξεις που σημειώνονται και επιστρέφει το αποτέλεσμα.

Απάντηση: Αφού όλοι οι τελεσταίοι είναι μονοψήφιοι ακέραιοι, απλά διατρέχουμε την ακολουθία χαρακτήρων s με βήμα 2 και ελέγχουμε αν ο τελεστής είναι '+' ή '-'. Δείτε τον κώδικα του strArithmetic.py.


def strArithmetics(s):
    val = int(s[0])
    for i in range(1,len(s),2):
        if s[i] == '+':
            val += int( s[i+1] )
        else:
            val -= int( s[i+1] )
    return val

# Let's try our code

s = '3-7+6-1+8'
print('The value of the expression', s, 'is', strArithmetics(s))

Πρόβλημα 10: Το τρίτο πρόσωπο του ενικού των ομαλών ρημάτων στα Αγγλικά σχηματίζεται σύμφωνα με τους εξής κανόνες: αν το ρήμα τελειώνει σε 'y', αυτό αφαιρείται και προστίθεται η κατάληξη 'ies'. Αν το ρήμα τελειώνει σε 'o', 'ch', 's', 'sh', 'x' ή 'z' τότε προστίθεται η κατάληξη 'es', διαφορετικά προστίθεται 's'. Γράψτε μία συνάρτηση person3 η οποία μπορεί να σχηματίσει το τρίτο πρόσωπο ρήματος σύμφωνα με τους κανόνες που δόθηκαν. Στη συνέχεια γράψτε ένα πρόγραμμα το οποίο ζητάει από τον χρήστη να πληκτρολογήσει ρήματα τα οποία αποθηκεύει σε μια λίστα. Η είσοδος σταματάει όταν ο χρήστης δώσει το ρήμα 'stop' (το οποίο δεν αποθηκεύεται). Χρησιμοποιώντας την παραπάνω συνάρτηση τυπώστε το τρίτο πρόσωπο του κάθε ρήματος.

Απάντηση: Η λύση του συγκεκριμένου προβλήματος απαιτεί τον έλεγχο του τελευταίου χαρακτήρα κάποιας ακολουθίας χαρακτήρων, ας πούμε, s, ο οποίος είναι βέβαια ο s[-1]. Οι δύο τελευταίοι χαρακτήρες του string s είναι s[-2:]. Δείτε τον κώδικα του person3.py.


def person3(verb):
    if verb[-1] == 'y':
        return verb[:-1] + 'ies'
    elif verb[-1] in 'osxz' or verb[-2:] == 'ch' or verb[-2:] == 'sh':
        return verb + 'es'
    else:
        return verb + 's'

# Let's try our code

L = []
while 1:
    verb = input('Enter a verb: ')
    if verb == 'stop': break
    L.append(verb)

for verb in L:
    print('Third person of', verb, 'is', person3(verb))

Πρόβλημα 11: Η λίστα M περιέχει τις κινήσεις ενός robot το οποίο αρχικά βρίσκεται στο σημείο \((0, 0)\). Κάθε κίνηση είναι μια πλειάδα στην οποία το πρώτο στοιχείο είναι μια από τις ακολουθίες χαρακτήρων 'UP', 'DOWN', 'LEFT' και ΄RIGHT' ενώ το δεύτερο στοιχείο είναι ένας θετικός πραγματικός αριθμός που δηλώνει την απόσταση που κινήθηκε το robot. Για παράδειγμα, αν M=[('LEFT',2.5),('UP',3),('LEFT',1)] το robot κινείται αρχικά 2.5 μονάδες αριστερά, ακολούθως 3 μονάδες επάνω και τέλος 1 μονάδα αριστερά. Γράψτε μια συνάρτηση robotMoves η οποία με όρισμα τη λίστα M να επιστρέφει τις συντεταγμένες της θέσης του robot και την απόσταση που έχει καλύψει. Στο παραπάνω παράδειγμα η συνάρτηση θα επιστρέφει τη θέση (3.5, 3) και την απόσταση 6.5.

Απάντηση: Αρκεί να διατρέξουμε τα στοιχεία της λίστας M και να διαβάσουμε την κατεύθυνση και την απόσταση. Δείτε τον κώδικα του robotMoves.py.


def robotMoves(M):
    x = 0; y = 0; dist = 0
    for move in M:
        d = move[1]
        if move[0] == 'UP':
            y += d
        elif move[0] == 'RIGHT':
            x += d
        elif move[0] == 'DOWN':
            y -= d
        elif move[0] == 'LEFT':
            x -= d
        else:
            continue
        dist += d

    return (x, y, dist)

# Let's try our code

moves = [('LEFT', 2.5), ('UP', 3), ('LEFT', 1), ('DOWN', 2.3), ('RIGHT', 1.2)]

x, y, dist = robotMoves(moves)
print('The robot is at x = {:.3f} y = {:.3f} and has covered a distance of {:.3f}'.format(x, y, dist))

Πρόβλημα 12: Γράψτε μία συνάρτηση n1n η οποία θα δέχεται έναν ακέραιο n και θα επιστρέφει την τιμή του αθροίσματος \( \frac{1}{n} + \frac{2}{n-1} + \frac{3}{n-2} + \cdots + \frac{n}{1} \). Γράψτε ένα πρόγραμμα το οποίο διαβάζει έναν ακέραιο αριθμό \(n\) και υπολογίζει και εκτυπώνει την τιμή του παραπάνω αθροίσματος.

Απάντηση: Αρκεί να διαπιστώσει κανείς τη σχέση αριθμητή και παρανομαστή στο παραπάνω άθροισμα. Σημειώστε ότι όταν ο αριθμητής έχει την τιμή $i$ τότε ο παρανομαστής έχει την τιμή $n+1-i$. Δείτε τον κώδικα του n1n.py.


def n1n(n):
    summ = 0
    for i in range(1,n+1): summ += i / (n+1-i)
    return summ

# Let's try our code

n = int(input('Enter a positive integer: '))
print('The sum is', n1n(n))

Πρόβλημα 13: Το Τμήμα επιτρέπει στους χρήστες των υπολογιστικών συστημάτων του να επιλέξουν το δικό τους κωδικό πρόσβασης, υπό την προϋπόθεση ότι ικανοποιεί τις εξής απαιτήσεις: (α) να αποτελείται από τουλάχιστον 12 χαρακτήρες (β) να περιέχει τουλάχιστον τρείς από τους χαρακτήρες '!&%#$@*' (γ) να περιέχει τουλάχιστον δύο ψηφία (δ) να περιέχει τουλάχιστον δύο φωνήεντα και (ε) να περιέχει το πολύ τρείς από τους χαρακτήρες 'zxcvbnm'. Γράψτε μια συνάρτηση acceptPass η οποία ελέγχει αν ένας κωδικός πρόσβασης είναι επιτρεπτός ή όχι, επιστρέφοντας 'Yes' or 'No', αντίστοιχα.

Απάντηση: Ελέγχουμε διαδοχικά κάθε μια από τις προϋποθέσεις. Αν διαπιστώσουμε ότι κάποια δεν ισχύει επιστρέφουμε αμέσως. Δείτε τον κώδικα του acceptPass.py.


def acceptPass(p):
    if len(p) < 12: return 'No'

    chars = '!&%#$@*'
    k = 0
    for c in p:
        if c in chars: k += 1
    if k < 3: return 'No'

    chars = '0123456789'
    k = 0
    for c in p:
        if c in chars: k += 1
    if k < 2: return 'No'

    chars = 'aeiou'
    k = 0
    for c in p:
        if c in chars: k += 1
    if k < 2: return 'No'

    chars = 'zxcvbnm'
    k = 0
    for c in p:
        if c in chars: k += 1
    if k > 3: return 'No'

    return 'Yes'

# Let's try our code

p = 'myreally123Long%$#@Password'
if acceptPass(p) == 'Yes':
    print('The password', p, 'is acceptable')
else:
    print('The password', p, 'is not acceptable')

Πρόβλημα 14: Γράψτε ένα πρόγραμμα το οποίο ζητάει από το χρήστη ακολουθίες χαρακτήρων μέχρι να συναντήσει την ακολουθία χαρακτήρων 'stop' (την οποία δεν αποθηκεύει). Στη συνέχεια το πρόγραμμα εκτυπώνει, αν υπάρχει, μια αλυσίδα λέξεων ως εξής: ξεκινώντας με την πρώτη λέξη, το πρώτο γράμμα της επόμενης λέξης είναι το τελευταίο της προηγούμενης. Για παράδειγμα, από την ακολουθία λέξεων: make an effort to climb to olympus, πρέπει να τυπωθεί η αλυσίδα λέξεων make effort to olympus.

Απάντηση: Αφού βάλουμε στην αλυσίδα την πρώτη λέξη, αναζητούμε τη λέξη η οποία ξεκινάει με το γράμμα της προηγούμενης. Δείτε τον κώδικα του chain.py.


def findChain(L):
    chain = []
    chain.append(L[0])
    lastl = L[0][-1]

    for word in L[1:]:
        if word[0] == lastl:
            chain.append(word)
            lastl = word[-1]

    return chain

# Let's try our code

L = []
while 1:
    word = input('Enter a word [\'stop\' to end input]: ')
    if word == 'stop': break
    L.append(word)

print('I found the following chain:', findChain(L))

Πρόβλημα 15: Οι Ρωμαίοι χρησιμοποιούσαν τα σύμβολα Μ για τον αριθμό 1000, D για το 500, C για το 100, L για το 50, X για το 10, V για το 5 και I για το 1. Γράψτε μια συνάρτηση romans η οποία με όρισμα έναν ακέραιο αριθμό επιστρέφει μια ακολουθία χαρακτήρων η οποία παριστάνει τον ίδιο αριθμό στο σύστημα των Ρωμαίων.

Απάντηση: Ξεκινώντας από τις χιλιάδες, προσθέτουμε διαδοχικά έναν από τους χαρακτήρες που απαρτίζουν την αναπαράσταση κάποιου αριθμού στο ρωμαϊκό σύστημα. Δείτε τον κώδικα του romans.py.


def romans(n):
    s = ''
    while n >= 1000: s += 'M'; n -= 1000
    if    n >=  500: s += 'D'; n -=  500
    while n >=  100: s += 'C'; n -=  100
    if    n >=   50: s += 'L'; n -=   50
    while n >=   10: s += 'X'; n -=   10
    if    n >=    5: s += 'V'; n -=    5;
    return s + n*'I'

# Let's try our code

n = 4657
print('The romans wrote', n, 'as', romans(n))

Πρόβλημα 16: Γράψτε μία συνάρτηση bob η οποία μεταφράζει μια λέξη σε Ακαταλαβίστικα, δηλαδή, διπλασιάζει κάθε σύμφωνο προσθέτοντας το χαρακτήρα 'ο' ανάμεσά τους. Για παράδειγμα, η λέξη 'potato' θα γίνει 'popototatoto' και η λέξη 'date' θα γίνει 'dodatote'. Γράψτε ένα πρόγραμμα για να χρησιμοποιήσετε τη συνάρτηση.

Απάντηση: Αρκεί να στη θέση κάθε συμφώνου, π.χ. του 'x', να βάλουμε την ακολουθία 'xox'. Δείτε τον κώδικα του sayWhat.py.


def sayWhat(s):
    t = ''
    for c in s:
       t += c
       if c not in 'aeiou': t += 'o' + c
    return t

s = 'potato'
print('Instead of', s, 'say:', sayWhat(s))