Unmatched elements in 2 different Arrays [duplicate] - c#

This question already has answers here:
Getting the "diff" between two arrays in C#?
(5 answers)
Closed 2 years ago.
Let say, I'm having 2 different arrays. The first is
x[] = {0, 1, 2, 3, 4} and the second one is y[] = {1, 3, 4}. The output that I expected is z[] = {0, 2}. How can i do this in C#?
Note: I'm also expecting the z[] elements are ordered ascending.

You can do it using Linq,
int[] x = new int[]{0, 1, 2, 3, 4};
int[] y = new int[]{1, 3, 4};
var result = x.Where(i => !y.Contains(i)).ToArray();
Console.WriteLine(string.Join(", ", result));
Using Set operation Except()
var result = x.Except(y);
If you are using Except(), then read below note from MSDN
This method returns those elements in first that don't appear in
second. It doesn't return those elements in second that don't appear
in first. Only unique elements are returned.
.Net Fiddle

The below code snippet gives, sorted unmatched elements in two arrays as result;
int[] x = new int[] { 1, 2, 2, 3, 4, 0 };
int[] y = new int[] { 1, 3, 3, 4, 5 };
int[] result = x.Except(y).Union(y.Except(x)).ToArray();
Array.Sort(result);
Console.WriteLine(string.Join(' ', result)); // Output: 0 2 5

Related

How to sum List<int> values but only by cells in C#?

For example I have this as List<List<int>>:
[2,4,4,2,5]
[1,3,6,3,8]
[0,3,9,0,0]
Should return the sum but only taking cells assuming that the cell count is always the same:
[3, 10, 19, 5, 13]
I am trying to find an easy way to solve this using Linq if it is possible because I am doing this with a lot of for loops and if conditions and I am complicating myself.
Is there a possible way to achieve this using Linq?
Linq approach
List<List<int>> items = new List<List<int>>() {
new List<int> { 2, 4, 4, 2, 5 },
new List<int> { 1, 3, 6, 3, 8 },
new List<int> { 0, 3, 9, 0, 0 } };
List<int> result = Enumerable.Range(0, items.Min(x => x.Count)).Select(x => items.Sum(y => y[x])).ToList();
var xx = new List<List<int>>() {
new List<int>() { 2, 4, 4, 2, 5 },
new List<int>() { 1, 3, 6, 3, 8 },
new List<int>() { 0, 3, 9, 0, 0 },
};
var y = xx.Aggregate((r, x) => r.Zip(x).Select(p => p.First + p.Second).ToList());
I am doing this with a lot of for loops and if conditions and I am complicating myself.
You can accomplish it by using a single for loop.
Two possible approaches to achieve that are:
Approach 1
Creating an array with a capacity equal to the size of either of the lists in the original list collection
Filling the array with 0s
Looping through all lists in the original list collection, aggregating the sum for each index
Approach 2
Creating a list based on the first list in the original list collection
Looping through all subsequent lists in the original list collection, aggregating the sum for each index
Both approaches benefit from the assumption given in the question post:
[...] assuming that the cell count is always the same
If your original list collection is defined as a List<List<int>>:
List<List<int>> valuesCollection = new()
{
new() { 2, 4, 4, 2, 5 },
new() { 1, 3, 6, 3, 8 },
new() { 0, 3, 9, 0, 0 },
};
, the two approaches may be implemented as follows:
Approach 1
var indexCount = valuesCollection[0].Count;
var sums = new int[indexCount];
Array.Fill(sums, 0);
foreach (var values in valuesCollection)
{
for (var i = 0; i < sums.Length; i++)
{
sums[i] += values[i];
}
}
Approach 2
Note: Uses namespace System.Linq
var sums = valuesCollection[0].ToList();
foreach (var values in valuesCollection.Skip(1))
{
for (var i = 0; i < sums.Count; i++)
{
sums[i] += values[i];
}
}
Using either approach, sums's resulting content will be { 3, 10, 19, 5, 13 }.
Example fiddle here.

How to convert a sequence of points to a sequence of ranges?

For example, I have a sequence of points
List points = new List {0, 1, 2, 4, 5 ,7};
And I want to convert it to a sequence of ranges (My type Range(leftPoint, rightPoint)). For the example, results are
List<Range> ranges: {0, 1} {1, 2} {2, 4} {4, 5} {5, 7}
You could use LINQ (presuming the list is already sorted):
List<Range> rangeList = Enumerable.Range(0, points.Count - 1)
.Select(i => new Range(points[i], points[i + 1]))
.ToList();
Why not just use a simple for-loop?
for(var i = 0; i < points.Count() - 1; i++)
ranges.Add(new Range(points[i], points[i+1]))
List<int> points = new List<int> { 0, 1, 2, 4, 5, 7 };
List<List<int>> listOfRanges = new List<List<int>>();
listOfRanges.Add(points.GetRange(0, 2));
listOfRanges.Add(points.GetRange(1, 2));
listOfRanges.Add(points.GetRange(2, 2));
listOfRanges.Add(points.GetRange(3, 2));
listOfRanges.Add(points.GetRange(4, 2));
You can iterate over it like so:
List<int> points = new List {0, 1, 2, 4, 5 ,7};
List<Range> listOfRanges = new List<Range>();
int index = 0
foreach (int value in points) {
listOfRanges.add(new Range(points[i], points[i+1]));
index++;
}
You might get a null comparison exception on the last iteration of the loop as points[i+1] doesn't exist - if so just handle this with a simple if statement.
This is assuming by points you mean a list of integers. I'll update if I find you meant something different.
You can use LINQ to zip the two lists that we get when we:
Take everything except the last element
Take everything except the first element
These correspond to (in the case of your example):
0, 1, 2, 4, 5
1, 2, 4, 5 ,7
Here is how you do it in code:
var result =
points
.Take(points.Count - 1) //points except last element
.Zip(
points.Skip(1), //points except first element
(l, r) => new Range(l, r))
.ToList();

How to Get the longest match found in number of sets, order is important

I need to find a way to return the longest match found in number of sets/lists (values returns only once) when the order of items is important.
the list is not cyclic.
A match is a sequence of values that exists in all the lists and maintains the same order of elements in all the lists.
e.g. 1:
List<int> list1 = new List<int> { 1, 2, 3, 4, 7, 9 };
List<int> list2 = new List<int> { 1, 2, 5, 6, 3, 4, 7, 9 };
List<int> list3 = new List<int> { 1, 2, 3, 6, 8, 9 };
List<int> list4 = new List<int> { 1, 2, 5, 6, 8, 9 };
result { 1, 2 }
e.g. 2:
List<int> list1 = new List<int> { 2, 3, 6, 8, 1, 18 };
List<int> list2 = new List<int> { 2, 3, 4, 6, 8, 1, 18, 19, 17, 14 };
List<int> list3 = new List<int> { 2, 5, 6, 8, 1, 18, 16, 13, 14 };
List<int> list4 = new List<int> { 2, 6, 8, 1, 18, 19, 17, 14 };
result { 6, 8, 1, 18 }
The match doesn't have to be found at the beginning or at the end and can be on any part of any list.
I hope that I explained my problem good enough :)
Thanks!
You can build a map from pairs of ints to a count of how many of the lists they appear adjacent in.
Pseudo-code:
For each list L {
For each adjacent pair (x, y) in L {
Counts[x, y] += 1
}
}
Now you can iterate through the first list (or the shortest list), and find the longest run such that each adjacent pair (x, y) in the run with Counts[x, y] showing that the pair appears in every list.
Pseudo-code:
run = []
best_run = []
For x in L[0] {
if len(run) is zero or Counts[run[len(run)-1], x] == number of lists {
run = run + x
} else {
run = [x]
}
if run is longer than best_run {
best_run = run
}
}
This works given the assumption in the question that no integer appears twice in the same list.
This algorithm runs in O(N) time, where N is the sum of the lengths of all the lists.
Here's my approach.
First I need a way to compare lists:
public class ListCompare<T> : IEqualityComparer<List<T>>
{
public bool Equals(List<T> left, List<T> right)
{
return left.SequenceEqual(right);
}
public int GetHashCode(List<T> list)
{
return list.Aggregate(0, (a, t) => a ^ t.GetHashCode());
}
}
Next a method to produce all subsequences of a source list:
Func<List<int>, IEnumerable<List<int>>> subsequences = xs =>
from s in Enumerable.Range(0, xs.Count)
from t in Enumerable.Range(1, xs.Count - s)
select xs.Skip(s).Take(t).ToList();
Now I can create a list of lists:
var lists = new [] { list1, list2, list3, list4, };
Finally a query that pulls it all together:
var answer =
lists
.Skip(1)
.Aggregate(
subsequences(lists.First()),
(a, l) => a.Intersect(subsequences(l), new ListCompare<int>()))
.OrderByDescending(x => x.Count)
.FirstOrDefault();
Given the sample data provided in the question this produces the expected results.
First generate an ordered combination of int from the shortest list
Compare the lists other than shortest list with the combination. For easy comparison of lists I just convert to string and use string.Contains()
Return immediately if find the match as the items left are next order or the shorter one.
public static List<int> GetLongestMatch(params List<int>[] all)
{
var shortest = all.Where(i => i.Count == all.Select(j => j.Count).Min()).First();
var permutations = (from length in Enumerable.Range(1, shortest.Count)
orderby length descending
from count in Enumerable.Range(1, shortest.Count - length + 1)
select shortest.Skip(count - 1).Take(length).ToList())
.ToList();
Func<List<int>, string> stringfy = (list) => { return string.Join(",", list.Select(i => i.ToString()).ToArray()); };
foreach (var item in permutations)
{
Debug.WriteLine(string.Join(", ", item.Select(i => i.ToString()).ToArray()));
if (all.All(list => stringfy(list).Contains(stringfy(item))))
{
Debug.WriteLine("Matched, skip process and return");
return item;
}
}
return new List<int>();
}
Usage
var result = GetLongestMatch(list1, list2, list3, list4);
Result
2, 3, 6, 8, 1, 18
2, 3, 6, 8, 1
3, 6, 8, 1, 18
2, 3, 6, 8
3, 6, 8, 1
6, 8, 1, 18
Matched, skip process and return

Get uniques elements

I have
int[] array1 = { 1, 2, 3 };
int[] array2 = { 2, 3, 4 };
Using var intersect = array1.Intersect(array2);I got
2
3
but I need to get
1
4
Can you give me any advice how I can do it using Linq?
array1.Union(array2).Except(array1.Intersect(array2))
Explanation:
First you calculate set union of two sequences: 1, 2, 3, 4
You are calculating intersection of sets: 2, 3
You are finding set difference between all items and intersection: 1, 4
Try this :
int[] array1 = { 1, 2, 3 };
int[] array2 = { 2, 3, 4 };
var result = array1.Concat(array2).Except(array1.Intersect(array2));
foreach (var item in result)
MessageBox.Show(item.ToString());
Output :
1
4

How to split array in two arrays?

I have one array and want split it in to two:
Now: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
New_1: [0, 2, 4, 6, 8]
New_2: [1, 3, 5, 7, 9]
So take the one element and skip the next element.
Look easy but how can i do it with C#?
Thanks a lot
You can use linq, Enumerable.Where and get the array with elements that have even and odd indexes.
var New_1 = arr.Where((c,i) => i % 2 == 0).ToArray();
var New_2 = arr.Where((c,i) => i % 2 != 0).ToArray();
You can get the index of element of collection and apply condition to check if index is even or odd and get the arrays according.
Enumerable.Where Method (IEnumerable, Func) filters a sequence of values based on a predicate.
Each element's index is used in the logic of the predicate function.
The first argument of predicate represents the element to test. The
second argument represents the zero-based index of the element within
source, msdn
How about something like
int[] arr = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int[] arr1 = arr.Where((x, i) => i % 2 == 0).ToArray();
int[] arr2 = arr.Where((x, i) => i % 2 == 1).ToArray();
int[] arr = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int i = 0;
List<int[]> twoArr = arr.GroupBy(x => i++ % 2).Select(g => g.ToArray()).ToList();

Categories

Resources