I have two arrays: array testAnswer holds "answers to a exam" and array inputAnswers holds "students answers to the exam".
When i run my code, it displays all the common elements of the two arrays(correct answers), and the uncommon elements (incorrect answers). However, instead of actually displaying the correct/incorrect answers, i want to be able to display the total number of correct/incorrect answers.
My code so far:
private void button1_Click(object sender, EventArgs e)
{
//Array holding answers to test
string[] testAnswer = new string[20] { "B", "D", "A", "A", "C", "A", "B", "A", "C", "D", "B", "C", "D", "A", "D", "C", "C", "B", "D", "A" };
string a = String.Join(", ", testAnswer);
//Reads text file line by line. Stores in array, each line of the file is an element in the array
string[] inputAnswer = System.IO.File.ReadAllLines(#"C:\Users\Momo\Desktop\UNI\Software tech\test.txt");
string b = String.Join(", ", inputAnswer);
//Increments through array elements in both arrays and checks for matching elements. Displays in listBox.
for (int i = 0; i < testAnswer.Length; i++)
{
if (testAnswer[i] == inputAnswer[i])
listBox1.Items.Add(inputAnswer[i]); // or testAnswer[i], as appropriate
}
//Increments through array elements in both arrays and checks for uncommon elements. Displays in listBox.
for (int i = 0; i < testAnswer.Length; i++)
{
if (testAnswer[i] != inputAnswer[i])
listBox2.Items.Add(inputAnswer[i]);
}
}
Here's how to get your results using LINQ:
var results =
testAnswer
.Zip(inputAnswer, (t, i) => new { t, i })
.Aggregate(new { Correct = 0, Incorrect = 0 },
(a, ti) => new
{
Correct = a.Correct + (ti.t == ti.i ? 1 : 0),
Incorrect = a.Incorrect + (ti.t != ti.i ? 1 : 0)
});
It'll produce an anonymous variable with this kind of result:
An alternative approach is:
var query =
testAnswer
.Zip(inputAnswer, (t, i) => t == i)
.ToLookup(x => x);
var results = new
{
Correct = query[true].Count(),
Incorrect = query[false].Count()
};
The following code will provide 2 integers at the end which will hold the answer:
private void button1_Click(object sender, EventArgs e)
{
string[] testAnswer = new string[20] { "B", "D", "A", "A", "C", "A", "B", "A", "C", "D", "B", "C", "D", "A", "D", "C", "C", "B", "D", "A" };
string a = String.Join(", ", testAnswer);
//Reads text file line by line. Stores in array, each line of the file is an element in the array
string[] inputAnswer = System.IO.File.ReadAllLines(#"C:\Users\Momo\Desktop\UNI\Software tech\test.txt");
string b = String.Join(", ", inputAnswer);
//Increments through array elements in both arrays and checks for matching elements.
//Displays in listBox.
for (int i = 0; i < testAnswer.Length; i++)
{
if (testAnswer[i] == inputAnswer[i])
listBox1.Items.Add(inputAnswer[i]); // or testAnswer[i], as appropriate
else
listBox2.Items.Add(inputAnswer[i]);
}
int correctAns = listbox1.Items.Count;
int wringAns = listbox2.Items.Count;
}
Common answers count would be Enumerable.Intersect result item count, uncommon - Enumerable.Except result item count.
Update: as long as it was mentioned in comments that it would produce wrong answers, proof that it would not:
var testAnswers = new[] { 1, 2, 3 };
var inputAnswers = new[] { 3, 2, 1 };
var commonAnswers = testAnswers
.Select((x, index) => Tuple.Create(x, index))
.Intersect(inputAnswers.Select((y, index) => Tuple.Create(y, index)));
Related
I can't quite figure it out how to loop through string array after the first initial loop has been done.
My code right now is:
string[] assignments = new string[] {"A", "B", "C", "D", "E", "F"};
Array.Resize<string>(ref assignments, 99);
for (int i = 0; i < 99; i++)
{
Console.WriteLine(assignments[i]);
}
However, it seems that Resizing the array doesn't accomplish much, since arrays values after the 6th value is non-existant.
I need it to keep looping more then once:
A
B
C
D
E
F A
B
C
D
E
F ... and so on, until the limit of 99 is reached.
Use the mod operator.
string[] assignments = new string[] {"A", "B", "C", "D", "E", "F"};
for (int i = 0; i < 99; i++)
{
Console.WriteLine(assignments[i % assignments.Length]);
}
.net fiddle
You can use the modulus operator which "computes the remainder after dividing its first operand by its second."
void Main()
{
string[] assignments = new string[] {"A", "B", "C", "D", "E", "F"};
for (int i = 0; i < 99; i++)
{
var j = i % 6;
Console.WriteLine(assignments[j]);
}
}
0 % 6 = 0
1 % 6 = 1
...
6 % 6 = 0
7 % 6 = 1
... etc.
The obligatory LINQ solution, this extension comes in handy:
public static IEnumerable<T> RepeatIndefinitely<T>(this IEnumerable<T> source)
{
while (true)
{
foreach (var item in source)
{
yield return item;
}
}
}
Now your task is very easy and readable:
var allAssignments = assignments.RepeatIndefinitely().Take(99);
You can use a foreach-loop with Console.WriteLine or build a string:
string result1 = string.Concat(allAssignments);
string result2 = string.Join(Environment.NewLine, allAssignments)
How about using mod
string[] assignments = new string[] { "A", "B", "C", "D", "E", "F" };
for (int i = 0; i < 99; i++)
{
Console.WriteLine(assignments[i%6]);
}
var array = new[] {new[]{'a', 'b', 'c'}, new[]{'d', 'e', 'f'}, new[]{'g', 'h', 'i'}};
var column = // should be like new[]{'b', 'e', 'h'} given index 1
How to do this?
Of course I could create a new list, populate it manually iterating through all the lines in a loop and convert it to an array but Isn't there a more laconic way?
LINQ is your friend.
It's what separates us C# developers from the mere mortals.
var array = new[] { new[] { "a", "b", "c" }, new[] { "d", "e", "f" }, new[] { "g", "h", "i" } };
var col1 = array.Select(x => x[1]);
//col1 contains "b", "e" and "h"
You can write an extension method for that:
public static T[] GetColumn<T>(this T[][] source, int columnIndex)
{
int length = source.Length;
var values = new T[length];
for (int i = 0; i < length; i++)
{
if(source[i].Length > columnIndex)
values[i] = source[i][columnIndex];
}
return values;
}
Then :
var column = array.GetColumn(1);
This also doesn't throw an IndexOutOfRange exception if one of your arrays contains less element than column number.
I have two arrays, array testAnswer holds "answers to a exam" and array inputAnswers holds "students answers to the exam".
I am trying to display the correct, and incorrect answers. In other words, trying to show what values testAnswer has that inputAnswers doesnt(incorrect answers), and also the values both arrays have in common(correct answers).
For this I have used the .Except and .Intersect method using linq; however I am getting this weird output:
B, D, A, C
Can anyone PLEASE help me, i've been at this for ages!
MY CODE:
private void button1_Click(object sender, EventArgs e)
{
string[] testAnswer = new string[20] { "B", "D", "A", "A", "C", "A", "B",
"A", "C", "D", "B", "C", "D", "A", "D", "C", "C", "B", "D", "A" };
string a = String.Join(", ", testAnswer);
// Reads text file line by line. Stores in array, each line of the
// file is an element in the array
string[] inputAnswer = System.IO.File
.ReadAllLines(#"C:\Users\Momo\Desktop\UNI\Software tech\test.txt");
string b = String.Join(", ", inputAnswer);
var inter = inputAnswer.Intersect(testAnswer);
foreach (var s in inter)
{
listBox1.Items.Add(s);
}
}
Intersect does set intersection, so it discards duplicate values. If you want to compare answers, a better option would be to go through the arrays in parallel:
for(int i=0; i<testAnswer.Length; i++) {
if(testAnswer[i] == inputAnswer[i])
listBox1.Items.Add(inputAnswer[i]); // or testAnswer[i], as appropriate
}
I have the following string arrays:
var array1 = new String[] { "A", "B", "C", "D" }
var array2 = new String[] { "B", "D" }
I need to do the following:
1) Find the item in array2 which appears firts in array1 (In this case is B);
2) Get the item in (1) and all the others which appear after it in array1.
So in this case I would get:
var array3 = new String[] { "B", "C", "D" }
I was trying to do it, in one step, using a lambda expression.
Is this possible?
var array3 = array1.SkipWhile(x => !array2.Contains(x)).ToArray();
How can I copy a string[] from another string[]?
Suppose I have string[] args. How can I copy it to another array string[] args1?
To create a completely new array with the same contents (as a shallow copy): call Array.Clone and just cast the result.
To copy a portion of a string array into another string array: call Array.Copy or Array.CopyTo
For example:
using System;
class Test
{
static void Main(string[] args)
{
// Clone the whole array
string[] args2 = (string[]) args.Clone();
// Copy the five elements with indexes 2-6
// from args into args3, stating from
// index 2 of args3.
string[] args3 = new string[5];
Array.Copy(args, 2, args3, 0, 5);
// Copy whole of args into args4, starting from
// index 2 (of args4)
string[] args4 = new string[args.Length+2];
args.CopyTo(args4, 2);
}
}
Assuming we start off with args = { "a", "b", "c", "d", "e", "f", "g", "h" } the results are:
args2 = { "a", "b", "c", "d", "e", "f", "g", "h" }
args3 = { "c", "d", "e", "f", "g" }
args4 = { null, null, "a", "b", "c", "d", "e", "f", "g", "h" }
Allocate space for the target array, that use Array.CopyTo():
targetArray = new string[sourceArray.Length];
sourceArray.CopyTo( targetArray, 0 );
The above answers show a shallow clone; so I thought I add a deep clone example using serialization; of course a deep clone can also be done by looping through the original array and copy each element into a brand new array.
private static T[] ArrayDeepCopy<T>(T[] source)
{
using (var ms = new MemoryStream())
{
var bf = new BinaryFormatter{Context = new StreamingContext(StreamingContextStates.Clone)};
bf.Serialize(ms, source);
ms.Position = 0;
return (T[]) bf.Deserialize(ms);
}
}
Testing the deep clone:
private static void ArrayDeepCloneTest()
{
//a testing array
CultureInfo[] secTestArray = { new CultureInfo("en-US", false), new CultureInfo("fr-FR") };
//deep clone
var secCloneArray = ArrayDeepCopy(secTestArray);
//print out the cloned array
Array.ForEach(secCloneArray, x => Console.WriteLine(x.DateTimeFormat.DateSeparator));
//modify the original array
secTestArray[0].DateTimeFormat.DateSeparator = "-";
Console.WriteLine();
//show the (deep) cloned array unchanged whereas a shallow clone would reflect the change...
Array.ForEach(secCloneArray, x => Console.WriteLine(x.DateTimeFormat.DateSeparator));
}