Trovare tutte le possibili permutazioni di una data stringa in python


93

Ho una stringa. Voglio generare tutte le permutazioni da quella stringa, cambiando l'ordine dei caratteri in essa. Ad esempio, dì:

x='stack'

quello che voglio è una lista come questa,

l=['stack','satck','sackt'.......]

Attualmente sto iterando sulla lista cast della stringa, selezionando 2 lettere a caso e trasponendole per formare una nuova stringa, e aggiungendola al set cast di l. In base alla lunghezza della stringa, sto calcolando il numero di permutazioni possibili e continuo le iterazioni fino a quando la dimensione impostata raggiunge il limite. Ci deve essere un modo migliore per farlo.

Risposte:


148

Il modulo itertools ha un metodo utile chiamato permutations (). La documentazione dice:

itertools.permutations (iterabile [, r])

Restituisce successive permutazioni di lunghezza r di elementi nell'iterabile.

Se r non è specificato o è Nessuno, allora r assume per impostazione predefinita la lunghezza dell'iterabile e vengono generate tutte le possibili permutazioni a lunghezza intera.

Le permutazioni vengono emesse in ordine lessicografico. Quindi, se l'input iterabile è ordinato, le tuple di permutazione verranno prodotte in ordine ordinato.

Tuttavia, dovrai unire le tue lettere permutate come stringhe.

>>> from itertools import permutations
>>> perms = [''.join(p) for p in permutations('stack')]
>>> perms

["stack", "stakc", "stcak", "stcka", "stkac", "stkca", "satck", "satkc", "sactk", "sackt", "saktc", "sakct", " sctak "," sctka "," scatk "," scakt "," sckta "," sckat "," sktac "," sktca "," skatc "," skact "," skcta "," skcat "," tsack " , "tsakc", "tscak", "tscka", "tskac", "tskca", "tasck", "taskc", "tacsk", "tacks", "taksc", "takcs", "tcsak", " tcska "," tcask "," tcaks "," tcksa "," tckas "," tksac "," tksca "," tkasc "," tkacs "," tkcsa "," tkcas "," astck ","astkc "," asctk "," asckt "," asktc "," askct "," atsck "," atskc "," atcsk "," atcks "," atksc "," atkcs "," acstk "," acskt " , "actsk", "actks", "ackst", "ackts", "akstc", "aksct", "aktsc", "aktcs", "akcst", "akcts", "cstak", "cstka", " csatk "," csakt "," cskta "," cskat "," ctsak "," ctska "," ctask "," ctaks "," ctksa "," ctkas "," castk "," caskt "," catsk " , "catks", "cakst", "cakts", "cksta", "cksat", "cktsa", "cktas", "ckast", "ckats", "kstac", "kstca", "ksatc","ksact", "kscta", "kscat", "ktsac", "ktsca", "ktasc", "ktacs", "ktcsa", "ktcas", "kastc", "kasct", "katsc", "katcs "," kacst "," kacts "," kcsta "," kcsat "," kctsa "," kctas "," kcast "," kcats "]

Se ti senti turbato dai duplicati, prova a inserire i tuoi dati in una struttura senza duplicati come set:

>>> perms = [''.join(p) for p in permutations('stacks')]
>>> len(perms)
720
>>> len(set(perms))
360

Grazie a @pst per aver sottolineato che questo non è ciò che tradizionalmente considereremmo un cast di tipo, ma più una chiamata al set()costruttore.


3
Nit: set(...)non "lancia". Piuttosto, genera (e restituisce) l'insieme che rappresenta la raccolta di input: una volta generata non ha alcuna associazione con la raccolta di input (ed è un oggetto diverso, non solo una vista diversa).

@ pst: Hmm tenderei a non essere d'accordo. So in Ada o Pascal che un cast è solo una nuova visualizzazione del tipo sugli stessi bit. Tuttavia, almeno da una prospettiva C, casting è un termine appropriato indipendentemente dal fatto che tu stia cambiando o meno la struttura sottostante dei dati. Si riferisce semplicemente alla conversione del tipo esplicita. Per favore, spiega il mio malinteso, se puoi.
macchina che desidera il

1
Typecasting . Mentre, come fai notare, può essere diverso da una semplice visione, mi piace cercare di mantenere i concetti separati per evitare confusione. Avrei dovuto menzionare "coercizione" esplicitamente nel mio primo commento, anche se prenderei in considerazione semplicemente set una funzione: list -> set.

1
Ho vista, boolè una funzione che Esamina a un bool (Vero / Falso) in base al momento dell'ingresso. Trovo che l'uso di "cast" qui sia spurio e fuorviante ...

1
Come aggiornamento interessante, la documentazione da allora è stata modificata per dire La funzione built-in bool () può essere utilizzata per convertire qualsiasi valore in un booleano , in particolare convertire piuttosto che cast. Ciò è accaduto nella versione successiva a questa discussione, portandomi a credere che questa discussione abbia portato a un cambiamento nei documenti!
macchina che brama il

46

Puoi ottenere tutti gli N! permutazioni senza molto codice

def permutations(string, step = 0):

    # if we've gotten to the end, print the permutation
    if step == len(string):
        print "".join(string)

    # everything to the right of step has not been swapped yet
    for i in range(step, len(string)):

        # copy the string (store as array)
        string_copy = [character for character in string]

        # swap the current index with the step
        string_copy[step], string_copy[i] = string_copy[i], string_copy[step]

        # recurse on the portion of the string that has not been swapped yet (now it's index will begin with step + 1)
        permutations(string_copy, step + 1)

Ben fatto. Funziona perfettamente
kishorer747

1
L'ho modificato leggermente, non è necessario scambiare le variabili se i == step
work_in_progress

4
Il runtime è O (n!) Perché ci sono n! permutazioni.
Aspen

Perché stai usando step == len(string)invece di step == len(string) - 1?
tulians

Perché allora gli ultimi 2 articoli non sarebbero mai stati scambiati. Prova 'abc' finché bec vengono scambiati.
Roman Riesen

16

Ecco un altro modo per eseguire la permutazione di stringhe con codice minimo. Fondamentalmente creiamo un ciclo e poi continuiamo a scambiare due caratteri alla volta, all'interno del ciclo avremo la ricorsione. Nota, stampiamo solo quando gli indicizzatori raggiungono la lunghezza della nostra stringa. Esempio: ABC i per il nostro punto di partenza e il nostro parametro di ricorsione j per il nostro ciclo

ecco un aiuto visivo su come funziona da sinistra a destra dall'alto verso il basso (è l'ordine di permutazione)

inserisci qui la descrizione dell'immagine

il codice :

def permute(data, i, length): 
    if i==length: 
        print(''.join(data) )
    else: 
        for j in range(i,length): 
            #swap
            data[i], data[j] = data[j], data[i] 
            permute(data, i+1, length) 
            data[i], data[j] = data[j], data[i]  


string = "ABC"
n = len(string) 
data = list(string) 
permute(data, 0, n)

5
Potrebbe essere utile menzionare che questa è la base del paradigma del bactracking .
AruniRC

Maggiori informazioni, codici uguali / simili: geeksforgeeks.org/… Mi piace di più il tuo esempio anche se con l'esempio grafico;)
CTS_AE

8

Gli utenti di Stack Overflow hanno già pubblicato alcune soluzioni efficaci, ma volevo mostrare un'altra soluzione. Questo lo trovo più intuitivo

L'idea è che per una data stringa: possiamo ricorrere all'algoritmo (pseudo-codice):

permutations = char + permutations (string - char) per char in string

Spero che aiuti qualcuno!

def permutations(string):
    """
    Create all permutations of a string with non-repeating characters
    """
    permutation_list = []
    if len(string) == 1:
        return [string]
    else:
        for char in string:
            [permutation_list.append(char + a) for a in permutations(string.replace(char, "", 1))]
    return permutation_list

4
Questo non funzionerà per i casi in cui sono presenti caratteri ripetuti (str.replace). Ad esempio: rqqx
Sanjay

Usa: [permutation_list.append (char + a) for a in permutations (string.replace (char, "", 1))]
user3761855

7

Ecco una semplice funzione per restituire permutazioni uniche:

def permutations(string):
    if len(string) == 1:
        return string

    recursive_perms = []
    for c in string:
        for perm in permutations(string.replace(c,'',1)):
            revursive_perms.append(c+perm)

    return set(revursive_perms)

6
1. Hai un errore di battitura: revursive_perms-> recursive_perms. 2. Risparmierebbe RAM e tempo se recursive_permsfosse un set piuttosto che un elenco che converti in un set nell'istruzione return. 3. Sarebbe più efficiente usare l'affettamento di stringhe invece di .replacecostruire l'arg alla chiamata ricorsiva di permutations. 4. Non è una buona idea usarlo stringcome nome di variabile perché ombreggia il nome del stringmodulo standard .
PM 2 Ring,

5

Ecco un altro approccio diverso da quello che hanno postato @Adriano e @illerucis. Questo ha un tempo di esecuzione migliore, puoi verificarlo tu stesso misurando il tempo:

def removeCharFromStr(str, index):
    endIndex = index if index == len(str) else index + 1
    return str[:index] + str[endIndex:]

# 'ab' -> a + 'b', b + 'a'
# 'abc' ->  a + bc, b + ac, c + ab
#           a + cb, b + ca, c + ba
def perm(str):
    if len(str) <= 1:
        return {str}
    permSet = set()
    for i, c in enumerate(str):
        newStr = removeCharFromStr(str, i)
        retSet = perm(newStr)
        for elem in retSet:
            permSet.add(c + elem)
    return permSet

Per una stringa arbitraria "dadffddxcf" ci sono voluti 1,1336 secondi per la libreria di permutazioni, 9,125 secondi per questa implementazione e 16,357 secondi per le versioni di @ Adriano e @illerucis. Ovviamente puoi ancora ottimizzarlo.


4

itertools.permutationsè buono, ma non gestisce bene le sequenze che contengono elementi ripetuti. Questo perché internamente permuta gli indici di sequenza ed è ignaro dei valori degli elementi di sequenza.

Certo, è possibile filtrare l'output di itertools.permutationsattraverso un set per eliminare i duplicati, ma è comunque sprecato tempo a generare quei duplicati, e se ci sono diversi elementi ripetuti nella sequenza di base ci saranno molti duplicati. Inoltre, l'utilizzo di una raccolta per contenere i risultati spreca RAM, annullando il vantaggio dell'utilizzo di un iteratore in primo luogo.

Fortunatamente esistono approcci più efficienti. Il codice seguente utilizza l'algoritmo del matematico indiano del XIV secolo Narayana Pandita, che può essere trovato nell'articolo di Wikipedia sulla permutazione . Questo antico algoritmo è ancora uno dei modi più veloci conosciuti per generare permutazioni in ordine, ed è abbastanza robusto, in quanto gestisce correttamente le permutazioni che contengono elementi ripetuti.

def lexico_permute_string(s):
    ''' Generate all permutations in lexicographic order of string `s`

        This algorithm, due to Narayana Pandita, is from
        https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order

        To produce the next permutation in lexicographic order of sequence `a`

        1. Find the largest index j such that a[j] < a[j + 1]. If no such index exists, 
        the permutation is the last permutation.
        2. Find the largest index k greater than j such that a[j] < a[k].
        3. Swap the value of a[j] with that of a[k].
        4. Reverse the sequence from a[j + 1] up to and including the final element a[n].
    '''

    a = sorted(s)
    n = len(a) - 1
    while True:
        yield ''.join(a)

        #1. Find the largest index j such that a[j] < a[j + 1]
        for j in range(n-1, -1, -1):
            if a[j] < a[j + 1]:
                break
        else:
            return

        #2. Find the largest index k greater than j such that a[j] < a[k]
        v = a[j]
        for k in range(n, j, -1):
            if v < a[k]:
                break

        #3. Swap the value of a[j] with that of a[k].
        a[j], a[k] = a[k], a[j]

        #4. Reverse the tail of the sequence
        a[j+1:] = a[j+1:][::-1]

for s in lexico_permute_string('data'):
    print(s)

produzione

aadt
aatd
adat
adta
atad
atda
daat
data
dtaa
taad
tada
tdaa

Naturalmente, se vuoi raccogliere le stringhe ottenute in una lista puoi farlo

list(lexico_permute_string('data'))

o nelle recenti versioni di Python:

[*lexico_permute_string('data')]

Splendidamente spiegato.
lmao

2

perché non fai semplicemente:

from itertools import permutations
perms = [''.join(p) for p in permutations(['s','t','a','c','k'])]
print perms
print len(perms)
print len(set(perms))

non ottieni duplicati come puoi vedere:

 ['stack', 'stakc', 'stcak', 'stcka', 'stkac', 'stkca', 'satck', 'satkc', 
'sactk', 'sackt', 'saktc', 'sakct', 'sctak', 'sctka', 'scatk', 'scakt', 'sckta',
 'sckat', 'sktac', 'sktca', 'skatc', 'skact', 'skcta', 'skcat', 'tsack', 
'tsakc', 'tscak', 'tscka', 'tskac', 'tskca', 'tasck', 'taskc', 'tacsk', 'tacks', 
'taksc', 'takcs', 'tcsak', 'tcska', 'tcask', 'tcaks', 'tcksa', 'tckas', 'tksac', 
'tksca', 'tkasc', 'tkacs', 'tkcsa', 'tkcas', 'astck', 'astkc', 'asctk', 'asckt', 
'asktc', 'askct', 'atsck', 'atskc', 'atcsk', 'atcks', 'atksc', 'atkcs', 'acstk', 
'acskt', 'actsk', 'actks', 'ackst', 'ackts', 'akstc', 'aksct', 'aktsc', 'aktcs', 
'akcst', 'akcts', 'cstak', 'cstka', 'csatk', 'csakt', 'cskta', 'cskat', 'ctsak', 
'ctska', 'ctask', 'ctaks', 'ctksa', 'ctkas', 'castk', 'caskt', 'catsk', 'catks', 
'cakst', 'cakts', 'cksta', 'cksat', 'cktsa', 'cktas', 'ckast', 'ckats', 'kstac', 
'kstca', 'ksatc', 'ksact', 'kscta', 'kscat', 'ktsac', 'ktsca', 'ktasc', 'ktacs', 
'ktcsa', 'ktcas', 'kastc', 'kasct', 'katsc', 'katcs', 'kacst', 'kacts', 'kcsta', 
'kcsat', 'kctsa', 'kctas', 'kcast', 'kcats']
    120
    120
    [Finished in 0.3s]

5
No, ottieni sempre duplicati (o peggio) se hai due o più lettere uguali. Questo è stato il caso dell'esempio di @ machineyearning, poiché ha usato la parola pile invece di pila . Ciò significa: la tua soluzione funziona solo per parole con caratteri univoci.
erik

2
def permute(seq):
    if not seq:
        yield seq
    else:
        for i in range(len(seq)):
            rest = seq[:i]+seq[i+1:]
            for x in permute(rest):
                yield seq[i:i+1]+x

print(list(permute('stack')))

2
Puoi spiegare perché la tua soluzione è migliore di quelle già fornite?
Noel Widmer,

Non ho detto che la mia soluzione è migliore delle altre. Ho appena fornito la mia soluzione per farlo.
Srivastava


1

Ecco una versione leggermente migliorata del codice di illerucis per restituire un elenco di tutte le permutazioni di una stringa scon caratteri distinti (non necessariamente nell'ordinamento lessicografico), senza utilizzare itertools:

def get_perms(s, i=0):
    """
    Returns a list of all (len(s) - i)! permutations t of s where t[:i] = s[:i].
    """
    # To avoid memory allocations for intermediate strings, use a list of chars.
    if isinstance(s, str):
        s = list(s)

    # Base Case: 0! = 1! = 1.
    # Store the only permutation as an immutable string, not a mutable list.
    if i >= len(s) - 1:
        return ["".join(s)]

    # Inductive Step: (len(s) - i)! = (len(s) - i) * (len(s) - i - 1)!
    # Swap in each suffix character to be at the beginning of the suffix.
    perms = get_perms(s, i + 1)
    for j in range(i + 1, len(s)):
        s[i], s[j] = s[j], s[i]
        perms.extend(get_perms(s, i + 1))
        s[i], s[j] = s[j], s[i]
    return perms

1

Ancora un'altra iniziativa e soluzione ricorsiva. L'idea è di selezionare una lettera come perno e quindi creare una parola.

# for a string with length n, there is a factorial n! permutations
alphabet = 'abc'
starting_perm = ''
# with recursion
def premuate(perm, alphabet):
    if not alphabet: # we created one word by using all letters in the alphabet
        print(perm + alphabet)
    else:
        for i in range(len(alphabet)): # iterate over all letters in the alphabet
            premuate(perm + alphabet[i], alphabet[0:i] + alphabet[i+1:]) # chose one letter from the alphabet

# call it            
premuate(starting_perm, alphabet)

Produzione:

abc
acb
bac
bca
cab
cba

0

Ecco una versione del generatore davvero semplice:

def find_all_permutations(s, curr=[]):
    if len(s) == 0:
        yield curr
    else:
        for i, c in enumerate(s):
            for combo in find_all_permutations(s[:i]+s[i+1:], curr + [c]):
                yield "".join(combo)

Penso che non sia così male!


0
def f(s):
  if len(s) == 2:
    X = [s, (s[1] + s[0])]
      return X
else:
    list1 = []
    for i in range(0, len(s)):
        Y = f(s[0:i] + s[i+1: len(s)])
        for j in Y:
            list1.append(s[i] + j)
    return list1
s = raw_input()
z = f(s)
print z

per favore prova ad aggiungere una descrizione.
Arun Vinoth

0

Ecco un'implementazione ricorsiva semplice e diretta;

def stringPermutations(s):
    if len(s) < 2:
        yield s
        return
    for pos in range(0, len(s)):
        char = s[pos]
        permForRemaining = list(stringPermutations(s[0:pos] + s[pos+1:]))
        for perm in permForRemaining:
            yield char + perm

1
Dovresti correggere il rientro. Non è necessario salvare i risultati della chiamata ricorsiva a stringPermutationsin un elenco: è possibile iterare direttamente su di esso, ad es for perm in stringPermutations(s[:pos] + s[pos+1:]):. Inoltre, è possibile semplificare il forciclo utilizzando enumerateal posto di range, ed eliminare l' char = s[pos]assegnazione: for pos, char in enumerate(s):.
PM 2 del

0
from itertools import permutations
perms = [''.join(p) for p in permutations('ABC')]

perms = [''.join(p) for p in permutations('stack')]

5
per favore prova ad aggiungere una descrizione.
Arun Vinoth

0
def perm(string):
   res=[]
   for j in range(0,len(string)):
       if(len(string)>1):
           for i in perm(string[1:]):
               res.append(string[0]+i)
       else:
           return [string];
       string=string[1:]+string[0];
   return res;
l=set(perm("abcde"))

Questo è un modo per generare permutazioni con la ricorsione, puoi capire facilmente il codice prendendo le stringhe "a", "ab" e "abc" come input.

Ottieni tutto N! permutazioni con questo, senza duplicati.


0

Tutti amano l'odore del proprio codice. Condivido solo quello che trovo il più semplice:

def get_permutations(word):
    if len(word) == 1:
        yield word

    for i, letter in enumerate(word):
        for perm in get_permutations(word[:i] + word[i+1:]):
            yield letter + perm

0

Questo programma non elimina i duplicati, ma penso che sia uno degli approcci più efficienti:

s=raw_input("Enter a string: ")
print "Permutations :\n",s
size=len(s)
lis=list(range(0,size))
while(True):
    k=-1
    while(k>-size and lis[k-1]>lis[k]):
        k-=1
    if k>-size:
        p=sorted(lis[k-1:])
        e=p[p.index(lis[k-1])+1]
        lis.insert(k-1,'A')
        lis.remove(e)
        lis[lis.index('A')]=e
        lis[k:]=sorted(lis[k:])
        list2=[]
        for k in lis:
                list2.append(s[k])
        print "".join(list2)
    else:
                break

0
def permute_all_chars(list, begin, end):

    if (begin == end):
        print(list)
        return

    for current_position in range(begin, end + 1):
        list[begin], list[current_position] = list[current_position], list[begin]
        permute_all_chars(list, begin + 1, end)
        list[begin], list[current_position] = list[current_position], list[begin]


given_str = 'ABC'
list = []
for char in given_str:
    list.append(char)
permute_all_chars(list, 0, len(list) -1)

per favore prova ad aggiungere una descrizione.
Arun Vinoth

0

Soluzione più semplice mediante permutazioni.

from itertools import permutations

def stringPermutate(s1):
    length=len(s1)
    if length < 2:
        return s1

    perm = [''.join(p) for p in permutations(s1)]

    return set(perm)

0

Tutte le possibili parole con lo stack

from itertools import permutations
for i in permutations('stack'):
    print(''.join(i))
permutations(iterable, r=None)

Restituisce successive permutazioni di lunghezza r di elementi nell'iterabile.

Se r non è specificato o è Nessuno, allora r assume per impostazione predefinita la lunghezza dell'iterabile e vengono generate tutte le possibili permutazioni a lunghezza intera.

Le permutazioni vengono emesse in ordine lessicografico. Quindi, se l'input iterabile è ordinato, le tuple di permutazione verranno prodotte in ordine ordinato.

Gli elementi vengono trattati come unici in base alla loro posizione, non al loro valore. Quindi, se gli elementi di input sono unici, non ci saranno valori di ripetizione in ogni permutazione.


0

Questa è una soluzione ricorsiva con la n!quale accetta elementi duplicati nella stringa

import math

def getFactors(root,num):
    sol = []
    # return condition
    if len(num) == 1:
            return [root+num]
    # looping in next iteration
    for i in range(len(num)):  
        # Creating a substring with all remaining char but the taken in this iteration
        if i > 0:
            rem = num[:i]+num[i+1:]
        else:
            rem = num[i+1:]
        # Concatenating existing solutions with the solution of this iteration
        sol = sol + getFactors(root + num[i], rem)
    return sol

Ho convalidato la soluzione tenendo conto di due elementi, il numero di combinazioni è n!e il risultato non può contenere duplicati. Così:

inpt = "1234"
results = getFactors("",inpt)

if len(results) == math.factorial(len(inpt)) | len(results) != len(set(results)):
    print("Wrong approach")
else:
    print("Correct Approach")

0

Con approccio ricorsivo.

def permute(word):
    if len(word) == 1:
        return [word]
    permutations = permute(word[1:])
    character = word[0]
    result = []
    for p in permutations:
        for i in range(len(p)+1):
            result.append(p[:i] + character + p[i:])
    return result




running code.

>>> permute('abc')
['abc', 'bac', 'bca', 'acb', 'cab', 'cba']

-1

Con ricorsione

# swap ith and jth character of string
def swap(s, i, j):
    q = list(s)
    q[i], q[j] = q[j], q[i]
    return ''.join(q)


# recursive function 
def _permute(p, s, permutes):
    if p >= len(s) - 1:
        permutes.append(s)
        return

    for i in range(p, len(s)):
        _permute(p + 1, swap(s, p, i), permutes)


# helper function
def permute(s):
    permutes = []
    _permute(0, s, permutes)
    return permutes


# TEST IT
s = "1234"
all_permute = permute(s)
print(all_permute)

Con approccio iterativo (utilizzando Stack)

# swap ith and jth character of string
def swap(s, i, j):
    q = list(s)
    q[i], q[j] = q[j], q[i]
    return ''.join(q)


# iterative function
def permute_using_stack(s):
    stk = [(0, s)]

    permutes = []

    while len(stk) > 0:
        p, s = stk.pop(0)

        if p >= len(s) - 1:
            permutes.append(s)
            continue

        for i in range(p, len(s)):
            stk.append((p + 1, swap(s, p, i)))

    return permutes


# TEST IT
s = "1234"
all_permute = permute_using_stack(s)
print(all_permute)

Con ordinati lessicograficamente

# swap ith and jth character of string
def swap(s, i, j):
    q = list(s)
    q[i], q[j] = q[j], q[i]
    return ''.join(q)


# finds next lexicographic string if exist otherwise returns -1
def next_lexicographical(s):
    for i in range(len(s) - 2, -1, -1):
        if s[i] < s[i + 1]:
            m = s[i + 1]
            swap_pos = i + 1

            for j in range(i + 1, len(s)):
                if m > s[j] > s[i]:
                    m = s[j]
                    swap_pos = j

            if swap_pos != -1:
                s = swap(s, i, swap_pos)
                s = s[:i + 1] + ''.join(sorted(s[i + 1:]))
                return s

    return -1


# helper function
def permute_lexicographically(s):
    s = ''.join(sorted(s))
    permutes = []
    while True:
        permutes.append(s)
        s = next_lexicographical(s)
        if s == -1:
            break
    return permutes


# TEST IT
s = "1234"
all_permute = permute_lexicographically(s)
print(all_permute)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.