Search code examples
regexkotlincomparemutablelist

Compare of values from two lists by use of regular expressions in Kotlin


I have two lists. The first contains original product data as following:

data class InputProductData (val optionFamilyInput: String?, val optionCodeInput: String?, val optionDescriptionInput: String?)
   
 val inputProductData = mutableListOf(
        InputProductData("AAA", "111","Chimney with red bricks"),
        InputProductData(null,"222","Two wide windows in the main floor"),
        InputProductData("CCCC",null,"Beautiful door in green color"),
        InputProductData("DDDD",null,"House with area 120 square meters"),
        InputProductData(null,"555","Old wood windows")
    )

Second list consists of customizing data. The list can have many identical option ids (first column).

    data class CustomizingProductOption(val id: Int, val optionName: String, val optionCategory: String, val optionFamily: String?, val optionCode: String?, val searchPattern: String?, val outputValue: String)

    val customizingProductOptions = mutableListOf(
    CustomizingProductOption(10001, "Chimney", "Additional options", "^AAA$", "", "^Chimney with", "Available"),
    CustomizingProductOption(10002, "Windows", "Basic options", "", "^222$", "^Two wide windows", "Available"),
    CustomizingProductOption(10002, "Windows", "Basic options", "", "^555$", "wood windows$", "Available"),
    CustomizingProductOption(10003, "Door color", "Basic options", "^CCCC$", "", "door in green color$", "green"),
    CustomizingProductOption(10004, "House area", "Basic options", "^DDD", "", "120 square meters", "120")
    )

The target is to check the product input data and to identify different product options. Whitin the following loop it is done by use of a business logic. There are 2 different constelations which can occure:

  1. Option family + regex within option description
  2. Option code + regex within option description
 data class IndicatedOptions(val id: Int, val output: String)
    val indicatedOptions: MutableList<IndicatedOptions>  = mutableListOf()

    for (i in 0 until inputProductData.size) {
        for (k in 0 until customizingProductOptions.size) {

            if(inputProductData[i].optionFamilyInput.toString().contains(Regex(customizingProductOptions[k].optionFamily.toString())) == true &&
            inputProductData[i].optionDescriptionInput.toString().contains(Regex(customizingProductOptions[k].searchPattern.toString())) == true ||

            inputProductData[i].optionCodeInput.toString().contains(Regex(customizingProductOptions[k].optionCode.toString())) == true &&
            inputProductData[i].optionDescriptionInput.toString().contains(Regex(customizingProductOptions[k].searchPattern.toString())) == true)  {

                indicatedOptions.add(IndicatedOptions(customizingProductOptions[k].id, customizingProductOptions[k].outputValue))
            }
        }
    }

    println("\n--- ALL INDICATED OPTIONS ---")
    indicatedOptions.forEach { println(it) }

    val indicatedOptionsUnique = indicatedOptions.distinct().sortedBy { it.id }
    println("\n--- UNIQUE INDICATED OPTIONS ---")
    indicatedOptionsUnique.forEach {println(it)}

QUESTION: Do you see any ways to optimize this codein order to get it more faster?


Solution

  • First, the "regex" code looks broken. Why do you test if a String contains a Regex? This is the wrong way around you would normally test a Regex to see if the target string is matched by the Regex.

    Ideas for performance

    1. Precompile your Regex in the constructor of CustomizingProductOption
    2. Your if logic is 4 logic ANDs. The code executes first to last in a logical expressions, so arrange the first test to be the one that is most selective (i.e. have the least number of matches).

    Ideas for readability

    1. use proper streams, e.g. inputProductData.map { customizingProductOptions.filter { LOGIC } }...
    2. Stop using unnecessary toString() on something that is already a String
    3. Stop testing if a boolean expression ==true

    Now with sample code:

    # Use Regex class here
    data class CustomizingProductOption(
        val id: Int, val optionName: String, val optionCategory: String,
        val optionFamily: Regex?, val optionCode: Regex?, val searchPattern: String?,
        val outputValue: String,
    )
    
    # Instantiate like this:
        CustomizingProductOption(
            10001, "Chimney", "Additional options", Regex("^AAA$"),
            null, "^Chimney with", "Available",
        ),
    
    # main code
    val indicatedOptions: List<IndicatedOptions> = inputProductData.map { productData ->
    
        customizingProductOptions.filter { option -> // this filter will only return matching options to product data
            productData.optionFamilyInput != null && option.optionFamily?.containsMatchIn(productData.optionFamilyInput) ?: false
            //&& other conditions
        }
            .map {option -> // transform to your desired output
                IndicatedOptions(
                    option.id,
                    option.outputValue,
                )
            }
    
    }.flatten() // you need this to flatten List<List<IndicatedOptions>>