Come ottengo il conteggio di un'enumerazione Swift?


Risposte:


173

A partire da Swift 4.2 (Xcode 10) è possibile dichiarare la conformità al CaseIterableprotocollo, questo funziona per tutte le enumerazioni senza valori associati:

enum Stuff: CaseIterable {
    case first
    case second
    case third
    case forth
}

Il numero di casi è ora ottenuto semplicemente con

print(Stuff.allCases.count) // 4

Per ulteriori informazioni, vedere


1
Nell'ultima versione di swift, l'errore di lancio "Tipo 'DAFFlow' non è conforme al protocollo 'RawRepresentable'". Perché mi costringe a seguirlo? Qualche idea?
Satyam,

@Satyam: che cos'è DAFFlow?
Martin R,

scusate ho dimenticato di dire che "DAFFlow" è un semplice enum che non eredita da nessun altro protocollo.
Satyam

1
Questa è la soluzione migliore, ma solo per chiarezza: gli sviluppatori Apple saranno davvero in grado di iniziare a usarlo solo quando Xcode 10 (e quindi Swift 4.2) usciranno dalla beta (quindi probabilmente intorno al 14 settembre 2018).
JosephH,

1
@DaniSpringer: i dettagli gory sono disponibili su github.com/apple/swift-evolution/blob/master/proposals/… . Ma di solito non è necessario quel tipo esplicitamente, a causa dell'inferenza di tipo automatica del compilatore.
Martin R,

143

Ho un post sul blog che approfondisce questo aspetto, ma fintanto che il tipo raw del tuo enum è un numero intero, puoi aggiungere un conteggio in questo modo:

enum Reindeer: Int {
    case Dasher, Dancer, Prancer, Vixen, Comet, Cupid, Donner, Blitzen
    case Rudolph

    static let count: Int = {
        var max: Int = 0
        while let _ = Reindeer(rawValue: max) { max += 1 }
        return max
    }()
}

16
Anche se bello perché non è necessario codificare un valore, questo creerà un'istanza di ogni valore di enum ogni volta che viene chiamato. Questo è O (n) invece di O (1). :(
Codice comandante

4
Questa è una buona soluzione per Int contigui. Preferisco una leggera modifica. Trasforma la proprietà conteggio statico in un metodo statico countCases () e assegnalo a una costante statica caseCount che è pigro e migliora le prestazioni con chiamate ripetute.
Tom Pelaia,

2
@ShamsAhmed: convertito il var calcolato in uno statico.
Nate Cook,

3
Che cosa succede se ti manca un valore nell'enum? ad es case A=1, B=3.
Sasho,

2
Ci sono 2 ipotesi oltre a enumavere un Intvalore non elaborato che hai dimenticato di menzionare: le enum di Swift con valori non elaborati Int non devono iniziare da 0 (anche se si tratta del comportamento predefinito) e i loro valori non elaborati possono essere arbitrari, non hanno incrementare di 1 (anche se questo è il comportamento predefinito).
Dávid Pásztor,

90

Aggiornamento di Xcode 10

Adotta il CaseIterableprotocollo nell'enum, fornisce una allCasesproprietà statica che contiene tutti i casi enum come a Collection. Basta usare la sua countproprietà per sapere quanti casi ha l'enum.

Vedi la risposta di Martin per un esempio (e vota le sue risposte piuttosto che le mie)


Attenzione : il metodo seguente non sembra funzionare più.

Non sono a conoscenza di alcun metodo generico per contare il numero di casi enum. Ho notato, tuttavia, che la hashValueproprietà dei casi enum è incrementale, a partire da zero e con l'ordine determinato dall'ordine in cui vengono dichiarati i casi. Quindi, l'hash dell'ultimo enum più uno corrisponde al numero di casi.

Ad esempio con questo enum:

enum Test {
    case ONE
    case TWO
    case THREE
    case FOUR

    static var count: Int { return Test.FOUR.hashValue + 1}
}

count ritorna 4.

Non posso dire se questa è una regola o se cambierà mai in futuro, quindi usa a tuo rischio e pericolo :)


48
Vivi per la funzionalità non documentata, muori per la funzionalità non documentata. Mi piace!
Nate Cook,

9
Non dovremmo davvero fare affidamento su hashValuesqueste cose; tutto ciò che sappiamo è che è un valore univoco casuale - potrebbe cambiare molto facilmente in futuro a seconda di alcuni dettagli di implementazione del compilatore; ma nel complesso, la mancanza di funzionalità di conteggio integrate è inquietante.
Zorayr,

16
Se non ti dispiace impostare esplicitamente case ONE = 0, puoi sostituirlo hashValuecon rawValue.
Kevin Qi,

3
la preoccupazione qui è l'uso di una proprietà non documentata di hashValue, quindi il mio suggerimento è di usare una proprietà documentata di rawValue.
Kevin Qi,

7
Hai già codificato il fatto di quale costante sia il valore più alto, migliore e più sicuro usare semplicemente qualcosa di simile static var count = 4piuttosto che lasciare il tuo destino nel destino delle future implementazioni di Swift
Dale

72

Definisco un protocollo riutilizzabile che esegue automaticamente il conteggio dei casi in base all'approccio pubblicato da Nate Cook.

protocol CaseCountable {
    static var caseCount: Int { get }
}

extension CaseCountable where Self: RawRepresentable, Self.RawValue == Int {
    internal static var caseCount: Int {
        var count = 0
        while let _ = Self(rawValue: count) {
            count += 1
        }
        return count
    }
}

Quindi posso riutilizzare questo protocollo ad esempio come segue:

enum Planet : Int, CaseCountable {
    case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
//..
print(Planet.caseCount)

1
Simpatica ed elegante, dovrebbe essere la risposta accettata IMHO
shannoga,

1
forse è meglio passare count++a count+=1poiché la ++notazione verrà rimossa in Swift 3
Aladin il

1
non si può fare lo stesso solo con static var caseCount: Int { get }? perché la necessità di static func?
pxpgraphics,

Che cosa succede se ti manca un valore nell'enum? ad es case A=1, B=3.
Sasho,

1
@Sasho, allora non funzionerà. Ciò richiede che i tuoi casi inizino da 0e non abbiano lacune.
NRitH

35

Crea un array allValues ​​statico come mostrato in questa risposta

enum ProductCategory : String {
     case Washers = "washers", Dryers = "dryers", Toasters = "toasters"

     static let allValues = [Washers, Dryers, Toasters]
}

...

let count = ProductCategory.allValues.count

Ciò è utile anche quando si desidera enumerare i valori e funziona per tutti i tipi di Enum


Sebbene non sia elegante come la soluzione di estensioni e molto manuale, credo che questo sia il più utile in quanto offre molto più del conteggio. Ti dà l'ordine dei valori e un elenco di tutti i valori.
Nader Eloshaiker,

2
Puoi anche aggiungere il conteggio all'enum facendo static let count = allValues.count. Quindi, allValuesse lo desideri, puoi rendere privato.
ThomasW

15

Se l'implementazione non ha nulla contro l'utilizzo di enumerazioni intere, è possibile aggiungere un valore membro aggiuntivo chiamato Countper rappresentare il numero di membri nell'enum - vedere l'esempio seguente:

enum TableViewSections : Int {
  case Watchlist
  case AddButton
  case Count
}

Ora puoi ottenere il numero di membri nell'enum chiamando, TableViewSections.Count.rawValueche restituirà 2 per l'esempio sopra.

Quando gestisci l'enum in un'istruzione switch, assicurati di lanciare un errore di asserzione quando incontri il Countmembro dove non te lo aspetti:

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  let currentSection: TableViewSections = TableViewSections.init(rawValue:section)!
  switch(currentSection) {
  case .Watchlist:
    return watchlist.count
  case .AddButton:
    return 1
  case .Count:
    assert(false, "Invalid table view section!")
  }
}

Mi piace quella soluzione in quanto cambia automaticamente il conteggio quando si aggiungono più valori enum. Tuttavia, tieni presente che questo funziona solo quando i valori grezzi dell'enum iniziano con 0.
joern

2
D'accordo, ci sono due restrizioni: deve essere un enum intero e deve iniziare da zero e continuare in modo incrementale.
Zorayr,

3
Pensavo che il punto centrale degli enumerazioni più potenti di Swift fosse che non avremmo dovuto usare gli stessi hack che
usavamo

14

Questo tipo di funzione è in grado di restituire il conteggio della tua enum.

Swift 2 :

func enumCount<T: Hashable>(_: T.Type) -> Int {
    var i = 1
    while (withUnsafePointer(&i) { UnsafePointer<T>($0).memory }).hashValue != 0 {
        i += 1
    }
    return i
}

Swift 3 :

func enumCount<T: Hashable>(_: T.Type) -> Int {
   var i = 1
   while (withUnsafePointer(to: &i, {
      return $0.withMemoryRebound(to: T.self, capacity: 1, { return $0.pointee })
   }).hashValue != 0) {
      i += 1
   }
      return i
   }

3
Questo non funziona più per Swift 3. Cercare di elaborare l'implementazione corretta, ma apparire vuoto
Cody Winton,

Questo sarà molto unfun il debug se l'indirizzo di memoria immediatamente adiacente all'estremità della enumè anche Hashable dello stesso tipo.
NRitH

10

Enum stringa con indice

enum eEventTabType : String {
    case Search     = "SEARCH"
    case Inbox      = "INBOX"
    case Accepted   = "ACCEPTED"
    case Saved      = "SAVED"
    case Declined   = "DECLINED"
    case Organized  = "ORGANIZED"

    static let allValues = [Search, Inbox, Accepted, Saved, Declined, Organized]
    var index : Int {
       return eEventTabType.allValues.indexOf(self)!
    }
}

contare : eEventTabType.allValues.count

indice: objeEventTabType.index

Godere :)


10

Oh ciao a tutti, per quanto riguarda i test unitari?

func testEnumCountIsEqualToNumberOfItemsInEnum() {

    var max: Int = 0
    while let _ = Test(rawValue: max) { max += 1 }

    XCTAssert(max == Test.count)
}

Questo combinato con la soluzione di Antonio:

enum Test {

    case one
    case two
    case three
    case four

    static var count: Int { return Test.four.hashValue + 1}
}

nel codice principale ti dà O (1) più ottieni un test fallito se qualcuno aggiunge un caso enum fivee non aggiorna l'implementazione di count.


7

Questa funzione si basa su 2 comportamenti correnti non documentati (Swift 1.1) enum:

  • Il layout di memoria di enumè solo un indice di case. Se il conteggio dei casi va da 2 a 256, lo è UInt8.
  • Se il enumbit è stato sottoposto a cast da un indice del caso non valido , lo hashValueè0

Quindi utilizzare a proprio rischio :)

func enumCaseCount<T:Hashable>(t:T.Type) -> Int {
    switch sizeof(t) {
    case 0:
        return 1
    case 1:
        for i in 2..<256 {
            if unsafeBitCast(UInt8(i), t).hashValue == 0 {
                return i
            }
        }
        return 256
    case 2:
        for i in 257..<65536 {
            if unsafeBitCast(UInt16(i), t).hashValue == 0 {
                return i
            }
        }
        return 65536
    default:
        fatalError("too many")
    }
}

Uso:

enum Foo:String {
    case C000 = "foo"
    case C001 = "bar"
    case C002 = "baz"
}
enumCaseCount(Foo) // -> 3

In rilascio e applicazione ad hoc CRASH
HotJard

Funziona in simulatore ma non su un vero dispositivo a 64 bit.
Daniel Nord,

5

Ho scritto una semplice estensione che fornisce a tutti gli enum in cui il valore grezzo è intero una countproprietà:

extension RawRepresentable where RawValue: IntegerType {
    static var count: Int {
        var i: RawValue = 0
        while let _ = Self(rawValue: i) {
            i = i.successor()
        }
        return Int(i.toIntMax())
    }
}

Sfortunatamente dà la countproprietà a OptionSetTypedove non funzionerà correttamente, quindi ecco un'altra versione che richiede esplicita conformità al CaseCountableprotocollo per qualsiasi enum quali casi vuoi contare:

protocol CaseCountable: RawRepresentable {}
extension CaseCountable where RawValue: IntegerType {
    static var count: Int {
        var i: RawValue = 0
        while let _ = Self(rawValue: i) {
            i = i.successor()
        }
        return Int(i.toIntMax())
    }
}

È molto simile all'approccio pubblicato da Tom Pelaia, ma funziona con tutti i tipi di numeri interi.


4

Certo, non è dinamico ma per molti usi puoi cavartela con una var statica aggiunta al tuo Enum

static var count: Int{ return 7 }

e poi usalo come EnumName.count


3
enum EnumNameType: Int {
    case first
    case second
    case third

    static var count: Int { return EnumNameType.third.rawValue + 1 }
}

print(EnumNameType.count) //3

O

enum EnumNameType: Int {
    case first
    case second
    case third
    case count
}

print(EnumNameType.count.rawValue) //3

* Su Swift 4.2 (Xcode 10) puoi usare:

enum EnumNameType: CaseIterable {
    case first
    case second
    case third
}

print(EnumNameType.allCases.count) //3

2

Nel mio caso d'uso, in una base di codice in cui più persone potrebbero aggiungere chiavi a un enum e questi casi dovrebbero essere tutti disponibili nella proprietà allKeys, è importante che allKeys sia validato rispetto alle chiavi dell'enum. Questo per evitare che qualcuno si dimentichi di aggiungere la propria chiave all'elenco di tutte le chiavi. La corrispondenza del conteggio dell'array allKeys (prima creato come set per evitare duplicati) con il numero di chiavi nell'enum assicura che siano tutte presenti.

Alcune delle risposte sopra mostrano il modo per raggiungere questo obiettivo in Swift 2, ma nessuna funziona in Swift 3 . Ecco la versione formattata di Swift 3 :

static func enumCount<T: Hashable>(_ t: T.Type) -> Int {
    var i = 1
    while (withUnsafePointer(to: &i) {
      $0.withMemoryRebound(to:t.self, capacity:1) { $0.pointee.hashValue != 0 }
    }) {
      i += 1
    }
    return i
}

static var allKeys: [YourEnumTypeHere] {
    var enumSize = enumCount(YourEnumTypeHere.self)

    let keys: Set<YourEnumTypeHere> = [.all, .your, .cases, .here]
    guard keys.count == enumSize else {
       fatalError("Missmatch between allKeys(\(keys.count)) and actual keys(\(enumSize)) in enum.")
    }
    return Array(keys)
}

A seconda del tuo caso d'uso, potresti voler semplicemente eseguire il test in fase di sviluppo per evitare il sovraccarico di usare allKeys su ogni richiesta


2

Perché rendi tutto così complesso? Il contatore PIÙ SEMPLICE di Int enum è aggiungere:

case Count

Alla fine. E ... viola - ora hai il conteggio - veloce e semplice


1
Questo a) aggiunge un caso enum estraneo eb) non funzionerà se il tipo grezzo dell'enum è diverso da Int.
Robert Atkins,

Questa in realtà non è una cattiva risposta. Come la precedente risposta di @Tom Pelaia, tuttavia, richiede che i valori grezzi inizino da 0e non abbiano lacune nella sequenza.
NRitH

1

Se non vuoi basare il tuo codice sull'ultimo enum puoi creare questa funzione all'interno del tuo enum.

func getNumberOfItems() -> Int {
    var i:Int = 0
    var exit:Bool = false
    while !exit {
        if let menuIndex = MenuIndex(rawValue: i) {
            i++
        }else{
            exit = true
        }
    }
    return i
}

1

Una versione di Swift 3 che funziona con i Inttipi enum:

protocol CaseCountable: RawRepresentable {}
extension CaseCountable where RawValue == Int {
    static var count: RawValue {
        var i: RawValue = 0
        while let _ = Self(rawValue: i) { i += 1 }
        return i
    }
}

Crediti: basato sulle risposte di bzz e Nate Cook.

Il generico IntegerType(in Swift 3 rinominato in Integer) non è supportato, in quanto è un tipo generico fortemente frammentato privo di molte funzioni. successornon è più disponibile con Swift 3.

Tieni presente che il commento di Code Commander alla risposta di Nate Cooks è ancora valido:

Anche se bello perché non è necessario codificare un valore, questo creerà un'istanza di ogni valore di enum ogni volta che viene chiamato. Questo è O (n) invece di O (1).

Per quanto ne so, al momento non esiste alcuna soluzione alternativa quando si utilizza questo come estensione del protocollo (e non si implementa in ogni enum come ha fatto Nate Cook) a causa delle proprietà memorizzate statiche non supportate nei tipi generici.

Comunque, per piccoli enumerati questo non dovrebbe essere un problema. Un tipico caso d'uso sarebbe il section.countper UITableViewscome già detto da Zorayr.


1

Estendendo la risposta di Matthieu Riegler, questa è una soluzione per Swift 3 che non richiede l'uso di generici e può essere facilmente chiamata usando il tipo enum con EnumType.elementsCount:

extension RawRepresentable where Self: Hashable {

    // Returns the number of elements in a RawRepresentable data structure
    static var elementsCount: Int {
        var i = 1
        while (withUnsafePointer(to: &i, {
            return $0.withMemoryRebound(to: self, capacity: 1, { return 
                   $0.pointee })
        }).hashValue != 0) {
            i += 1
        }
        return i
}

0

Ho risolto questo problema da solo creando un protocollo (EnumIntArray) e una funzione di utilità globale (enumIntArray) che semplifica l'aggiunta di una variabile "All" a qualsiasi enum (usando swift 1.2). La variabile "all" conterrà un array di tutti gli elementi nell'enum in modo da poter usare all.count per il conteggio

Funziona solo con enum che usano valori grezzi di tipo Int ma forse può fornire qualche ispirazione per altri tipi.

Affronta anche i problemi di "gap nella numerazione" e "tempo eccessivo per iterare" che ho letto sopra e altrove.

L'idea è di aggiungere il protocollo EnumIntArray al tuo enum e quindi definire una variabile statica "all" chiamando la funzione enumIntArray e fornendogli il primo elemento (e l'ultimo se ci sono lacune nella numerazione).

Poiché la variabile statica viene inizializzata solo una volta, il sovraccarico di passare attraverso tutti i valori non elaborati colpisce il programma solo una volta.

esempio (senza lacune):

enum Animals:Int, EnumIntArray
{ 
  case Cat=1, Dog, Rabbit, Chicken, Cow
  static var all = enumIntArray(Animals.Cat)
}

esempio (con lacune):

enum Animals:Int, EnumIntArray
{ 
  case Cat    = 1,  Dog, 
  case Rabbit = 10, Chicken, Cow
  static var all = enumIntArray(Animals.Cat, Animals.Cow)
}

Ecco il codice che lo implementa:

protocol EnumIntArray
{
   init?(rawValue:Int)
   var rawValue:Int { get }
}

func enumIntArray<T:EnumIntArray>(firstValue:T, _ lastValue:T? = nil) -> [T]
{
   var result:[T] = []
   var rawValue   = firstValue.rawValue
   while true
   { 
     if let enumValue = T(rawValue:rawValue++) 
     { result.append(enumValue) }
     else if lastValue == nil                     
     { break }

     if lastValue != nil
     && rawValue  >  lastValue!.rawValue          
     { break }
   } 
   return result   
}

0

Oppure puoi semplicemente definire l' _countesterno dell'enum e collegarlo staticamente:

let _count: Int = {
    var max: Int = 0
    while let _ = EnumName(rawValue: max) { max += 1 }
    return max
}()

enum EnumName: Int {
    case val0 = 0
    case val1
    static let count = _count
}

In questo modo, indipendentemente dal numero di enum che crei, verrà creato una sola volta.

(cancella questa risposta se lo staticfa)


0

Il seguente metodo proviene da CoreKit ed è simile alle risposte suggerite da altri. Funziona con Swift 4.

public protocol EnumCollection: Hashable {
    static func cases() -> AnySequence<Self>
    static var allValues: [Self] { get }
}

public extension EnumCollection {

    public static func cases() -> AnySequence<Self> {
        return AnySequence { () -> AnyIterator<Self> in
            var raw = 0
            return AnyIterator {
                let current: Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: self, capacity: 1) { $0.pointee } }
                guard current.hashValue == raw else {
                    return nil
                }
                raw += 1
                return current
            }
        }
    }

    public static var allValues: [Self] {
        return Array(self.cases())
    }
}

enum Weekdays: String, EnumCollection {
    case sunday, monday, tuesday, wednesday, thursday, friday, saturday
}

Quindi devi solo chiamare Weekdays.allValues.count.


0
enum WeekDays : String , CaseIterable
{
  case monday = "Mon"
  case tuesday = "Tue"
  case wednesday = "Wed"
  case thursday = "Thu"
  case friday = "Fri"
  case saturday = "Sat"
  case sunday = "Sun"
}

var weekdays = WeekDays.AllCases()

print("\(weekdays.count)")

-1
struct HashableSequence<T: Hashable>: SequenceType {
    func generate() -> AnyGenerator<T> {
        var i = 0
        return AnyGenerator {
            let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
            if next.hashValue == i {
                i += 1
                return next
            }
            return nil
        }
    }
}

extension Hashable {
    static func enumCases() -> Array<Self> {
        return Array(HashableSequence())
    }

    static var enumCount: Int {
        return enumCases().enumCount
    }
}

enum E {
    case A
    case B
    case C
}

E.enumCases() // [A, B, C]
E.enumCount   //  3

ma fai attenzione con l'uso su tipi non enumici. Alcune soluzioni alternative potrebbero essere:

struct HashableSequence<T: Hashable>: SequenceType {
    func generate() -> AnyGenerator<T> {
        var i = 0
        return AnyGenerator {
            guard sizeof(T) == 1 else {
                return nil
            }
            let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
            if next.hashValue == i {
                i += 1
                return next
            }

            return nil
        }
    }
}

extension Hashable {
    static func enumCases() -> Array<Self> {
        return Array(HashableSequence())
    }

    static var enumCount: Int {
        return enumCases().count
    }
}

enum E {
    case A
    case B
    case C
}

Bool.enumCases()   // [false, true]
Bool.enumCount     // 2
String.enumCases() // []
String.enumCount   // 0
Int.enumCases()    // []
Int.enumCount      // 0
E.enumCases()      // [A, B, C]
E.enumCount        // 4

-1

Può usare una costante statica che contiene l'ultimo valore dell'enumerazione più uno.

enum Color : Int {
    case  Red, Orange, Yellow, Green, Cyan, Blue, Purple

    static let count: Int = Color.Purple.rawValue + 1

    func toUIColor() -> UIColor{
        switch self {
            case .Red:
                return UIColor.redColor()
            case .Orange:
                return UIColor.orangeColor()
            case .Yellow:
                return UIColor.yellowColor()
            case .Green:
                return UIColor.greenColor()
            case .Cyan:
                return UIColor.cyanColor()
            case .Blue:
                return UIColor.blueColor()
            case .Purple:
                return UIColor.redColor()
        }
    }
}

-3

Questo è minore, ma penso che una soluzione O (1) migliore sarebbe la seguente ( SOLO se il tuo enum sta Intiniziando da x, ecc.):

enum Test : Int {
    case ONE = 1
    case TWO
    case THREE
    case FOUR // if you later need to add additional enums add above COUNT so COUNT is always the last enum value 
    case COUNT

    static var count: Int { return Test.COUNT.rawValue } // note if your enum starts at 0, some other number, etc. you'll need to add on to the raw value the differential 
}

La risposta attualmente selezionata, credo ancora, sia la migliore risposta per tutti gli enum, a meno che tu non stia lavorando, Intallora ti consiglio questa soluzione.


3
Aggiungere un valore al tuo enum che in realtà non rappresenta il tipo di enum è un cattivo odore di codice. Trovo difficile persino giustificare l'inclusione di un "ALL" o "NONE" anche se a volte può essere allettante. Includere un "COUNT" solo per aggirare questo problema è molto puzzolente.
Michael Peterson,

1
Puzzolente? Se vuoi chiamarlo così sicuro. Performante? Sì. Spetta allo sviluppatore decidere i pro ei contro. Questa è in realtà la stessa risposta alla risposta di Zorayr di cui sopra che approfondisce la questione, e anche la nuova risposta accettata è simile. Ma fino a che rapido aggiunge un api per questo; questo è ciò che alcuni di noi hanno deciso di utilizzare. È possibile aggiungere una funzione che convalida il valore enum che guardè contro COUNTe genera un errore, restituisce false, ecc. Per risolvere il problema relativo alla rappresentazione dei tipi.
Drmorgan,
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.