How do i loop string array in c# more than once? - c#

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]);
}

Related

Removing almost-duplicates from nested list

If I have the following sublists, how can I remove 'duplicates' so that I only have L1, L2 and L3 remaining? I don't mind which variant remains, as long as the duplicates are gone.
List<List<string>> mylist = new List<List<string>>();
List<string> L1 = new List<string> { "a", "b", "c" };
List<string> L2 = new List<string> { "d", "e", "f" };
List<string> L3 = new List<string> { "g", "h", "i" };
List<string> L4 = new List<string> { "c", "a", "b" };
List<string> L5 = new List<string> { "a", "c", "b" };
List<string> L6 = new List<string> { "f", "d", "e" };
It's worth mentioning that I'm removing the duplicates to improve performance in another part of my program, so anything too intensive would not be appropriate. Thanks!
you can use Linq by applying Distinct function with a custom comparer like the following code:
1 - Create Custom generic comparer for List<T>:
public class GenericComparer<T> : IEqualityComparer<List<T>>
{
public bool Equals(List<T> x, List<T> y)
{
return x.Count == y.Count && x.All(xx => y.Contains(xx));
}
public int GetHashCode(List<T> obj)
{
int hashCode = 0;
foreach(T str in obj)
{
hashCode ^= str.GetHashCode();
}
return hashCode;
}
}
2 - call Distinct function with StringListComparer like :
List<List<string>> mylist = new List<List<string>>()
{
new List<string> { "a", "b", "c" },
new List<string> { "d", "e", "f" },
new List<string> { "g", "h", "i" },
new List<string> { "c", "a", "b" },
new List<string> { "a", "c", "b" },
new List<string> { "f", "d", "e" },
};
var result = mylist.Distinct(new GenericComparer<string>()).ToList();
3 - Demo
foreach(List<string> strList in result)
{
Console.WriteLine(string.Join(",", strList));
}
4- Result
a,b,c
d,e,f
g,h,i
If you have a list of integer, you can call Distinct method like :
var result1 = mylist1.Distinct(new GenericComparer<int>()).ToList();
I hope this help you out.

May I use foreach in this case? How to WriteLine string "cool"?

I learn C# and make the code. How to print word "cool" with foreach operator:
static void Main(string[] args)
{
string [ ] arr = {"a", "c", "a", "o", "a", "o", "a", "l"};
string sum = "";
foreach (string x in arr)
{
sum += x * 2;
}
}
Console.WriteLine(sum);
I cannot use x * 2 , if I use only sum += x, Output is "acaoaoal". How to receive output "cool" by using foreach?
for (int i = 1; i < arr.Length; i += 2)
{
sum += arr[i];
}
You need for loop and start it from i=1 with step +2.
If your assignment is to use foreach you need to add another variable as counter, and you need to check it if it is even number.
int count = -1;
foreach(string x in arr)
{
count++;
if(count % 2 == 0)
continue;
sum += x;
}
Be aware if the string array is too big you should use StringBuilder for concatenation of strings.
How to do it with linq:
var result = arr.Select((x, i) => i % 2 == 1 ? x:"").Where(x=>!string.IsNullOrEmpty(x)).ToArray();
Console.WriteLine(string.Join("", result));
This could be easier if you use a for loop with step instead of for each.
for (var i = 1; i < 8; i += 2) {
sum += strArr [i];
}
forEach loop doesn't a have counter. You should explicitly specify your own:
static void Main(string[] args)
{
string [ ] arr = {"a", "c", "a", "o", "a", "o", "a", "l"};
StringBuilder sb = new StringBuilder();
int index = 0;
foreach (string element in arr)
{
if(index % 2 != 0)
sb.Append(element);
index++;
}
Console.WriteLine(sb);
StringBuilder output = new StringBuilder();
Array.ForEach(arr, x => { if(Array.IndexOf(arr,x) % 2 != 0) output.Append(x); });
This works:
string[] arr = { "a", "c", "a", "o", "a", "o", "a", "l" };
string sum = "";
foreach (string x in arr.Where((c, n) => n % 2 == 1))
{
sum += x;
}
Console.WriteLine(sum);
You can even write it as:
string[] arr = { "a", "c", "a", "o", "a", "o", "a", "l" };
string sum = String.Join("", arr.Where((c, n) => n % 2 == 1));
Console.WriteLine(sum);

How to get a column of a 2D array in C#?

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.

Displaying total number of common and uncommon elements between two arrays?

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)));

Copy one string array to another

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));
}

Categories

Resources