'Average test score from result array with varying group sizes

I am working on a problem where I have to calculate the average from a bunch of test results with the following criteria. -his program was tested on several test case and each test case has the following results.."OK", "Wrong answer", "TimeOut", "Runtime error" -test cases were organized into groups numbered by consecutive natural numbers -his program scored points for a group only when the result of every test case in the group was "OK" for instance if test case names are test1, test2a, test2b, test2c, test3, test4. In this case test2a, test2b, test2c all form one group and must all score OK to receive a collective point.

Write a function

class Solution{
public int solution (String[] test, String[] result){}
}
//example:
test[0] = "test1a",  result[0] = "Wrong answer"
test[1] = "test2",  result[1] = "OK"
test[2] = "test1b",  result[2] = "Runtime error"
test[3] = "test1c",  result[0] = "OK"
test[4] = "test3",  result[4] = "Time limit exceeded" 
//result above is 33.

Assume integer is within range 1-300 -arrays test and result have the same length -every test case appears just once -test case are ordered by consecutive natural integers from 1. -test cases in groups containing at least two tests are differentiated by a lowercase suffix in alphabetical order from a. -each string in results contains one of "OK", "Wrong answer", "TimeOut", "Runtime error"

Right now I wrote code to strip the test String array and get the integers for each test group. Then I created an Integer, Integer HashMap where I check the integers I gathered after using regex and check to ensure all test cases in a group are "OK" before assigning a 100 to them

import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Codechef
{
public static int solution(String[] test, String[] result)
{
    HashMap<Integer, Integer> scoreMap =  new HashMap<Integer, Integer>();

    int[] stripped = new int[test.length];

    //stripped the String of numbers..
    for(int i = 0; i < test.length;i++)
    {
       stripped[i] = Integer.parseInt(test[i].replaceAll("[^0-9]", ""));
    }

    //working with just the numbers from the test groups array
    for(int i = 0; i < stripped.length; i++)
    {
        if(scoreMap.containsKey(stripped[i]))
        {
            if(result[i].equals("OK"))
                scoreMap.put(stripped[i], 100);

            else
                scoreMap.put(stripped[i], 0);
        }

        else
        {
            if(result[i].equals("OK"))
                scoreMap.put(stripped[i], 100);

            else
                scoreMap.put(stripped[i], 0);
        }

    }

    int correctAnswers = 0;
    for(int val: scoreMap.values())
    {
        if(val == 100)
            correctAnswers++;
    }

    double avg =  correctAnswers/scoreMap.size() * 100;

    return (int)Math.floor(avg); 

    //return Math.floor(correctAnswers/scoreMap.size() * 100);

}


public static void main (String[] args) throws java.lang.Exception
{
    // your code goes here
    String[] test1 = {"test1", "test2a", "test2b", "test4", "test2c", "test3", "test5", "test6", "test7"};
    String[] results1 = {"OK", "OK", "Wrong answer", "OK", "Wrong answer", "Wrong answer", "OK", "TimeOut","Runtime error"}; 
    int average1 =  solution(test1, results1);

    String[] test2 = {"stackoverflow1", "stackoverflow2a", "stackoverflow2b", "stackoverflow4", "stackoverflow2c", "stackoverflow3", "stackoverflow5", "stackoverflow6", "stackoverflow7"};
    String[] results2 = {"Runtime error", "OK", "Wrong answer", "OK", "TimeOut", "Wrong answer", "OK", "Timeout","TimeOut"};

    int average2 =  solution(test2, results2);

    String[] test3 = {"test1", "test2a", "test2b", "test4", "test2c", "test3", "test5", "test6", "test7"};
    String[] results3 = {"OK", "OK", "TimeOut", "OK", "TimeOut", "OK", "TimeOut", "Runtime error","OK"}; 
    int average3 =  solution(test3, results3);

    System.out.println("Avg1 = " + average1);
    System.out.println("Avg2 = " + average2);
    System.out.println("Avg3 = " + average3);

}

}



Solution 1:[1]

If i have understood you correctly, a test case can either consist of a single test or multiple tests, formly speaking of a test suite.

Lets introduce the following two classes:

private static class TestSuiteResult {
    private String name;
    private List<TestResult> results = new ArrayList<>();

    public TestSuiteResult(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public List<TestResult> getResults() {
        return results;
    }
}

private static class TestResult {
    private String name;
    private String result;

    public TestResult(String name, String result) {
        this.name = name;
        this.result = result;
    }

    public String getName() {
        return name;
    }

    public String getResult() {
        return result;
    }
}

Next, lets try to parse the input String[] tests and String[] results to above classes. The regular expression test(\d*)([a-z])? matches any input that start with test, followed by any number of digits, optionally followed by a character from a-z. The capturing groups are used to extract the needed pieces.

String regex = "(\\w*?)(\\d*)([a-z])?";
Pattern pattern = Pattern.compile(regex);

Map<String, TestResult> testResults = new HashMap<>();
Map<String, TestSuiteResult> testSuiteResults = new HashMap<>();

for (int i = 0; i < tests.length; i++) {

    String test = tests[i];
    Matcher matcher = pattern.matcher(test);

    // check for illegal test name
    if (!matcher.matches()) {
        continue;
    }

    String name = matcher.group(1);
    String digitPart = matcher.group(2);
    String character = matcher.group(3);

    if (character != null) {
        // multi test
        String suiteName = name + digitPart;
        TestSuiteResult suite = testSuiteResults.get(digitPart);
        TestSuiteResult suite = testSuiteResults.get(suiteName);
        if (suite == null) {
            suite = new TestSuiteResult(suiteName);
            testSuiteResults.put(suite.getName(), suite);
        }
        String result = results[i];
        TestResult multi = new TestResult(character, result);
        suite.getResults().add(multi);
    } else {
        // single test
        String result = results[i];
        TestResult single = new TestResult(test, result);
        testResults.put(single.getName(), single);
    }
}

Nextup, we can calculate the total amount of tests and from the total amount of valid tests. I have considered a test suite as a single test here, which is only valid if all of its contained tests are valid.

int totalAmountOfTests = testResults.size() + testSuiteResults.size();

int validTests = 0;
for (Map.Entry<String, TestResult> entry : testResults.entrySet()) {
    if (entry.getValue().getResult().equals("OK")) {
        validTests++;
    }
}
for (Map.Entry<String, TestSuiteResult> entry : testSuiteResults.entrySet()) {
    List<TestResult> suiteResults = entry.getValue().getResults();
    boolean valid = true;
    for (TestResult suiteResult : suiteResults) {
        if (!suiteResult.getResult().equals("OK")) {
            valid = false;
        }
    }
    if (valid) {
        validTests++;
    }
}

Now, finally we can calculate the average amount of tests that passed. When casting average to an int we round to the lower digit.

double average = (double) totalAmountOfTests / validTests;
int averageRounded = (int) average;

The complete, working example is available here.

Solution 2:[2]

Well i tried this with Python...

    #!/bin/python3

import math
import os
import random
import re
import sys
# Complete the rotLeft function below.
def rotLeft(T, R):
    my_dict=dict()
    templist=[]
    subgroups=[]
    fianl=0

    for i in range(len(T)):
        my_dict[T[i]]=R[i]

    value=dict()
    for x,y in my_dict.items():
        templist.append(x)


    templist.sort()

    tempgroups= templist[-1]
    if tempgroups[-1].isdigit():
        totalgroups=(int)(tempgroups[-1])
    else:
        totalgroups=(int)(tempgroups[-2])

    for x in templist:
        if x[-1].isdigit():
            continue
        else:
            subgroups.append(x)
    test=""

    i=0
    while i < len(subgroups):
        test=subgroups[i]
        count=0
        totalcount=0
        for item in subgroups:
            if item[-2] == test[-2]:
                totalcount=totalcount+1
            if my_dict[item] == "OK" and item[-2] == test[-2]:
                count = count + 1

        i=i+1
        if totalcount == count:
            fianl=fianl+100 /count


    for x,y in my_dict.items():
        if x[-1].isdigit() and y == "OK":
            fianl=fianl+100


    print ((int)(fianl / totalgroups))








if __name__ == '__main__':
    T = ['test1', 'test3', 'test4', 'test5', 'test5a', 'test5b', 'test6', 'test7a','test7b']
    R = ['Wrong answer', 'OK', 'OK', 'Time limit exceeded', 'OK', 'Wrong answer', 'OK', 'OK','OK']

    result = rotLeft(T, R)

Solution 3:[3]

So, the important part is task ID. Let's group answers by task id:
1=[Wrong answer, Runtime error, OK], 2=[OK], 3=[Time limit exceeded]

Next we can convert answers to boolean if it's OK or not:
1=[false, false, true], 2=[true], 3=[false]

Then reduce them:
1=false, 2=true, 3=false

And calculate the final result:
1 * 100 / 3

Kotlin code:

fun solution(T: Array<String>, R: Array<String>): Int {
    return T.asSequence()
        .map { Regex("\\w+(\\d+)").find(it) }
        .filterNotNull()
        .map { it.destructured.component1().toInt() }
        .zip(R.asSequence().map { it == "OK" })
        .groupingBy { it.first }
        .fold(true) { acc, el -> acc && el.second }
        .let { map -> map.values.count { it } * 100 / map.size }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Santhosh Christopher
Solution 3