2017-07-07 2 views
1

Im folgenden Kotlin Beispiel, würde Ich mag zu „memoize“ -Funktion das Element (das Ergebnis der Cache) matches:memoization der Member-Funktion von Kotlin Datenklasse

import java.util.regex.Pattern 

data class MyDataClass(val name: String = "John Doe", 
         val description: String = "Famous person") { 

    //TODO memoize this 
    fun matches(searchTerm: String): Boolean { 
     println("Calculating...") 
     return name.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) 
       || description.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) 
    } 
} 

fun main(args: Array<String>) { 
    val myData = MyDataClass() 
    println(myData.matches("John")) 
    println(myData.matches("John")) 
    println(myData.matches("John")) 
    println(myData.matches("Famous")) 
    println(myData.matches("Famous")) 
    println(myData.matches("Famous"))  
} 

Soweit ich sehen kann, Kotlin < = 1.1 unterstützt keine Memo-Erstellung. Natürlich können Sie Ihre eigene Memo-Funktion schreiben oder eine Bibliothek wie z.B.

Mit funKTionale muss ich keine eigene Memo-Funktion schreiben und kam zu dieser Lösung. Leider sieht es aus "boilerplatey":

import org.funktionale.memoization.memoize 
import java.util.regex.Pattern 

data class MyMemoizedDataClassV1(val name: String = "John Doe", 
           val description: String = "Famous person") { 

    private val memoizedMatches: (String, String, String) -> Boolean = 
      { name: String, description: String, searchTerm: String -> 
       println("Calculating...") 
       name.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) 
         || description.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) 
      }.memoize() 

    fun matches(searchTerm: String): Boolean { 
     return memoizedMatches(name, description, searchTerm) 
    } 
} 

fun main(args: Array<String>) { 
    val myData = MyMemoizedDataClassV1() 
    println(myData.matches("John")) 
    println(myData.matches("John")) 
    println(myData.matches("John")) 
    println(myData.matches("Famous")) 
    println(myData.matches("Famous")) 
    println(myData.matches("Famous")) 
} 

Ich denke an eine schöneren Lösung wie

data class MyDataClass(val name: String = "John Doe", 
         val description: String = "Famous person") { 

    fun matches(searchTerm: String): Boolean { 
     println("Calculating...") 
     return name.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) 
       || description.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) 
    }.memoize() //TODO how? 
} 

Aber, wie diese zu erreichen?

+1

Bedeutet memoization Caching-Ergebnis? – Joshua

+0

@Joshua, ja. Danke für den Kommentar. Ich habe die Frage bearbeitet und "Zwischenergebnis cachen" hinzugefügt. – Peti

Antwort

2

Sie viel von den vorformulierten von Ihrem Funktionale Code entfernen:

data class MyMemoizedDataClassV1(val name: String = "John Doe", 
           val description: String = "Famous person") { 

    val matches = { searchTerm: String -> 
     println("Calculating...") 
     name.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) 
      || description.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) 
    }.memoize() 

} 

Sie haben Zugriff auf name und description aus der Datenklasse in Ihrem Lambda, so dass Sie sie nicht als Parameter übergeben müssen. Wenn Sie sie als Parameter verwenden, würde die memoize-Funktion sie im Schlüssel verwenden, um die Antwort zu suchen, aber das ist nutzlos, weil sie sich nie ändern (wie sie mit val definiert sind). Auch

, weil matches den Typ hat (String) -> Boolean, können Sie einfach die Funktion-Eigenschaft aussetzen direkt in Ihre Datenklasse, statt eine andere Funktion zu schaffen, die es nennt. Schließlich habe ich einige Typen entfernt, die der Compiler ableiten kann.

+1

Vielen Dank @marstran, ich habe gerade viel gelernt! – Peti

1

a und b sind val, so dass Sie das Ergebnis in einer

data class MyDataClass(val a: Int = 1, 
         val b: Int = 2) { 
    val sum = a + b 
} 

val zuweisen Wenn die Berechnung teuer ist, können Sie faul verwenden Berechnung zu verzögern.

data class MyDataClass(val a: Int = 1, 
         val b: Int = 2) { 
    val sum: Int by lazy { 
     a + b 
    } 
} 

Edit: Neue Antwort für editierte Frage

interface StringMatchable { 
    fun matches(searchTerm: String): Boolean 
} 

data class MyDataClass(val name: String = "John Doe", 
         val description: String = "Famous person") : StringMatchable by 
CacheStringMatchable({ 
    searchTerm -> 
    name.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) 
      || description.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) 
}) 

class CacheStringMatchable(private val function: (String) -> Boolean) : StringMatchable { 
    private val map: MutableMap<String, Boolean> = mutableMapOf() 
    override fun matches(searchTerm: String): Boolean { 
     return map.computeIfAbsent(searchTerm, function) 
    } 
} 

, ein Verfahren zu delegieren, ist es durch die Schnittstelle derzeit nur möglich. Es kann also wahrscheinlich nicht generisch geschrieben werden (d. H. 1 Cache-Klasse für alle).

Edit2: Wenn dies die einzige Klasse ist matches() benötigt, dann ist hier eine einfachere Antwort

data class MyDataClass(val name: String = "John Doe", 
         val description: String = "Famous person") { 
    private val map: MutableMap<String, Boolean> = mutableMapOf() 
    fun matches(searchTerm: String): Boolean { 
     return map.computeIfAbsent(searchTerm, { 
      searchTerm -> 
      name.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) 
        || description.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) 
     }) 
    } 
} 
+0

Dank @Joshua, ausgezeichnete Lösung für das gegebene Beispiel. Ich habe das Beispiel übertrieben vereinfacht. In meinem realen Anwendungsfall benötigt die Memberfunktion 1 oder mehr Parameter, um etwas aus dem internen Zustand zu berechnen. Ich muss die Frage anpassen oder eine zweite Frage mit einem "Tricker" Beispiel öffnen ... – Peti

+1

@Peti Ich kann die Antwort bearbeiten, wenn Sie weitere Details angeben =) – Joshua

+0

Ich habe das Beispiel geändert. Jetzt hat die Elementfunktion 1 Parameter. – Peti

Verwandte Themen