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();
Related
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.
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.
First I want to know if at least one element in a first list can be found in a second list.
List<string> list1 = new[] { "A", "C", "F", "H", "I" };
List<string> list2 = new[] { "B", "D", "F", "G", "L" };
I am using below code to do this -
bool isFound = list1.Intersect(list2).Any();
But I want to know which element is that. Like in above case it is 'F'
What is the best way to do this?
You just use Intersect only:
var result = list1.Intersect(list2);
Try:
List<string> list1 = new List<string> { "A", "C", "F", "H", "I" };
List<string> list2 = new List<string> { "B", "D", "F", "G", "L" };
String sel = list1.Intersect(list2).FirstOrDefault()??"";
Console.WriteLine(sel);
Try my Demo
You can use Enumerable.Intersect method only, you don't need to use Any in your case.
Produces the set intersection of two sequences.
List<string> list1 = new List<string>(){ "A", "C", "F", "H", "I" };
List<string> list2 = new List<string>(){ "B", "D", "F", "G", "L" };
var intersect = list1.Intersect(list2);
foreach (var i in intersect)
{
Console.WriteLine(i);
}
Output will be;
F
Here is a DEMO.
Instead of bool variable You can take another list variable like:
List<string> list3 Variable to get list of items which are forund in second list and assign the result to list3
List<string> list3= list1.Intersect(list2).ToList();
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)));
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));
}