'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 |