Show non matched values from two arrays - c#

How do I put into the collection of ListBox those items that doesn't have a pair from each array?
For example:
first array = 100 500
second array = 100 200 300 400 500 600 700 800
Now, how do I show those non matched values (200,400,600,700,800) into ListBox?

You can use LINQ and Except method:
int[] result = secondArray.Except(firstArray).ToArray();
yourListBox.DataSource = result;
Also if you want to include values in firstArray that are not in secondArray go with the following query:
var result = firstArray.Except(secondArray).Union(secondArray.Except(firstArray)).ToArray();

HashSet<int> can easily do set operations like this. Go check out the docs on that class and I'm sure you'll have an answer. I believe you will be interested in the method SymmetricExceptWith

Might not be the most efficient, but you can do
var firstArray = new int[2] {100,500};
var secondArray = new int[8] {100,200,300,400,500,600,700,800};
var x = secondArray.Except(firstArray);
foreach(var item in x)
Console.WriteLine(item);

This is more or less a duplicate of Get the symmetric difference from generic lists.
var differences = listA.Except(listB).Union(listB.Except(listA));

Related

How to return two arrays using one WHERE statement

Is it possible to combine these two statements into one which returns "contains" and "not contains" results?
string[] words = { "one", "two", "three", "four" };
int[] numbers = { 4, 5, 6 };
string[] contains =
(from w in words
where numbers.Contains(w.Length)
select w).ToArray();
string[] notContains =
(from w in words
where !numbers.Contains(w.Length)
select w).ToArray();
You can do:
var groups = words.GroupBy(w => numbers.Contains(w.Length));
This will return at most two groups: one with the key false and one with the key true.
Edit
As vc 74 pointed out in the comments, numbers.Contains is an O(n) operation when numbers is an array. Converting it to a HashSet instead will make this a constant time operation, which is asymptotically much faster.
So, here's the updated code:
var numberHS = new HashSet<int>(numbers);
var groups = words.GroupBy(w => numberHS.Contains(w.Length));
You can also use ToLookup:
var containsLengthLookup = words.ToLookup(w => numbers.Contains(w.Length));
string[] contains = containsLengthLookup[true].ToArray();
string[] notContains = containsLengthLookup[false].ToArray();
If one of both is empty (or the source array is empty) you get an empty string[].
There's one difference to GroupBy, the lookup is cached. So it's more efficient if you use it multiple times, but the information is just a snapshot. If you modify words or numbers this isn't reflected in the lookup.

Create intervals of data with LINQ

I have an issue in C# that I can't figure out how to solve:
I have a set of data that consist of a TimeStamp and a value.
This is a sample dataset:
<Timestamp>2014-01-06T17:40:08.000Z</TimeStamp>
<Value>200</Value>
<Timestamp>2014-01-06T17:40:09.000Z</TimeStamp>
<Value>234</Value>
<Timestamp>2014-01-06T17:40:11.000Z</TimeStamp>
<Value>214</Value>
<Timestamp>2014-01-06T17:40:12.000Z</TimeStamp>
<Value>264</Value>
<Timestamp>2014-01-06T17:40:13.000Z</TimeStamp>
<Value>300</Value>
<Timestamp>2014-01-06T17:40:15.000Z</TimeStamp>
<Value>276</Value>
What I need to do is to somehow get the average of the values by every 30 seconds. Notice that the recordings of data is not necessarily every second. This is what makes it hard for me to imagine how to do this without having an insecurity in the results.
Is this achievable through a LINQ statement or do you have other suggestions?
Assuming you can figure out how to parse the XML, and you have a collection of objects with Time and Value. For example, I'll use this collection:
var now = DateTime.Now;
var random = new Random();
var times = Enumerable.Range(1, 10000).Select(i => new
{
Time = now.AddHours(random .NextDouble()),
Value = i
});
Using a helper method DateTime RoundUp(DateTime dt, TimeSpan d), and GroupBy:
var interval = TimeSpan.FromSeconds(30);
var intervalAverageValues =
times.GroupBy(t => RoundUp(t.Time, interval))
.Select(g => new
{
AverageValue = g.Average(t => t.Value),
IntervalEndTime = g.Key,
Count = g.Count()
});
Consider this pseudo answer :)
Take your list of values and their timestamps and produce a list of Tuple<int, int>{} this is assuming your values are ints. Where first int is index and second int is the value;
As you are filling the tuples list you need to take the total seconds component of your timestamp and divide it by 30. The result should be rounded to closest int.
At this point you have a list of tuples that has values paired with their corresponding '30 second' group index;
Use a simple group linq to produce your averages. Basically you loop over your groups and sum the values. Then divide by group's item count;
This is brute force approach somewhat. I'm sure there are smarter ways to do this.

.NET Create an array with unknown size until runtime (or a better way of array slicing)

I have a block of several lines of text. I've split this like so:
var lines = mytext.Split(new string[] {Environment.NewLine},
StringSplitOptions.None);
Now, I need to get a subset of the lines - namely a remainder. In Python I would do something like this:
>>> lines = ['zero', 'one', 'two', 'three', 'four']
>>> lines[3:]
['three', 'four']
But this is obviously not legal syntax in .NET.
So I found the Array.Copy method, and figured, a hah! I'll just do this:
var newlines = new string[lines.Length-someAmount]{};
to get me a list I can copy into.
but then I got an error saying that I can't make an array like that - the number has to be known at compile time! Okay, well, I'll try something else - silly, but it should work, right?
var newlinesList = new List<string>(lines.Length-someAmount);
var newlines = newlinesList.ToArray();
Then I can use:
Array.Copy(lines, startIndex, bodylines, 0, lines.Length-startIndex);
Except for one problem - apparently ToArray() filters out the empty/null values, so I can't actually copy it.
So how do I create an array with the size unknown until runtime, or even better, how can I simply slice an array?
There are several ways. Perhaps the easiest is with LINQ:
var newArray = lines.Skip(3).ToArray();
And if you wanted to take just two items (assuming the lines array had more than 5), you'd write:
var newArray = lines.Skip(3).Take(2).ToArray();
Or, if you only wanted the first three:
var newArray = lines.Take(3).ToArray();
Which, I think, pretty much covers array slicing.
You absolutely can do that – just don't pass a list of elements:
var newlines = new string[lines.Length-someAmount];
int cursor = 3; //Number of element to start copying from
string[] newlines = new string[lines.Length - cursor];
Array.Copy(lines, cursor, newlines, 0, lines.Length - cursor);

What is the fastest non-LINQ algorithm to 'pair up' matching items from multiple separate lists?

IMPORTANT NOTE
To the people who flagged this as a duplicate, please understand we do NOT want a LINQ-based solution. Our real-world example has several original lists in the tens-of-thousands range and LINQ-based solutions are not performant enough for our needs since they have to walk the lists several times to perform their function, expanding with each new source list.
That is why we are specifically looking for a non-LINQ algorithm, such as the one suggested in this answer below where they walk all lists simultaneously, and only once, via enumerators. That seems to be the best so far, but I am wondering if there are others.
Now back to the question...
For the sake of explaining our issue, consider this hypothetical problem:
I have multiple lists, but to keep this example simple, let's limit it to two, ListA and ListB, both of which are of type List<int>. Their data is as follows:
List A List B
1 2
2 3
4 4
5 6
6 8
8 9
9 10
...however the real lists can have tens of thousands of rows.
We next have a class called ListPairing that's simply defined as follows:
public class ListPairing
{
public int? ASide{ get; set; }
public int? BSide{ get; set; }
}
where each 'side' parameter really represents one of the lists. (i.e. if there were four lists, it would also have a CSide and a DSide.)
We are trying to do is construct a List<ListPairing> with the data initialized as follows:
A Side B Side
1 -
2 2
- 3
4 4
5 -
6 6
8 8
9 9
- 10
Again, note there is no row with '7'
As you can see, the results look like a full outer join. However, please see the update below.
Now to get things started, we can simply do this...
var finalList = ListA.Select(valA => new ListPairing(){ ASide = valA} );
Which yields...
A Side B Side
1 -
2 -
4 -
5 -
6 -
8 -
9 -
and now we want to go back-fill the values from List B. This requires checking first if there is an already existing ListPairing with ASide that matches BSide and if so, setting the BSide.
If there is no existing ListPairing with a matching ASide, a new ListPairing is instantiated with only the BSide set (ASide is blank.)
However, I get the feeling that's not the most efficient way to do this considering all of the required 'FindFirst' calls it would take. (These lists can be tens of thousands of items long.)
However, taking a union of those lists once up front yields the following values...
1, 2, 3, 4, 5, 6, 8, 9, 10 (Note there is no #7)
My thinking was to somehow use that ordered union of the values, then 'walking' both lists simultaneously, building up ListPairings as needed. That eliminates repeated calls to FindFirst, but I'm wondering if that's the most efficient way to do this.
Thoughts?
Update
People have suggested this is a duplicate of getting a full outer join using LINQ because the results are the same...
I am not after a LINQ full outer join. I'm after a performant algorithm.
As such, I have updated the question.
The reason I bring this up is the LINQ needed to perform that functionality is much too slow for our needs. In our model, there are actually four lists, and each can be in the tens of thousands of rows. That's why I suggested the 'Union' approach of the IDs at the very end to get the list of unique 'keys' to walk through, but I think the posted answer on doing the same but with the enumerators is an even better approach as you don't need the list of IDs up front. This would yield a single pass through all items in the lists simultaneously which would easily out-perform the LINQ-based approach.
This didn't turn out as neat as I'd hoped, but if both input lists are sorted then you can just walk through them together comparing the head elements of each one: if they're equal then you have a pair, else emit the smallest one on its own and advance that list.
public static IEnumerable<ListPairing> PairUpLists(IEnumerable<int> sortedAList,
IEnumerable<int> sortedBList)
{
// Should wrap these two in using() per Servy's comment with braces around
// the rest of the method.
var aEnum = sortedAList.GetEnumerator();
var bEnum = sortedBList.GetEnumerator();
bool haveA = aEnum.MoveNext();
bool haveB = bEnum.MoveNext();
while (haveA && haveB)
{
// We still have values left on both lists.
int comparison = aEnum.Current.CompareTo(bEnum.Current);
if (comparison < 0)
{
// The heads of the two remaining sequences do not match and A's is
// lower. Generate a partial pair with the head of A and advance the
// enumerator.
yield return new ListPairing() {ASide = aEnum.Current};
haveA = aEnum.MoveNext();
}
else if (comparison == 0)
{
// The heads of the two sequences match. Generate a pair.
yield return new ListPairing() {
ASide = aEnum.Current,
BSide = bEnum.Current
};
// Advance both enumerators
haveA = aEnum.MoveNext();
haveB = bEnum.MoveNext();
}
else
{
// No match and B is the lowest. Generate a partial pair with B.
yield return new ListPairing() {BSide = bEnum.Current};
// and advance the enumerator
haveB = bEnum.MoveNext();
}
}
if (haveA)
{
// We still have elements on list A but list B is exhausted.
do
{
// Generate a partial pair for all remaining A elements.
yield return new ListPairing() { ASide = aEnum.Current };
} while (aEnum.MoveNext());
}
else if (haveB)
{
// List A is exhausted but we still have elements on list B.
do
{
// Generate a partial pair for all remaining B elements.
yield return new ListPairing() { BSide = bEnum.Current };
} while (bEnum.MoveNext());
}
}
var list1 = new List<int?>(){1,2,4,5,6,8,9};
var list2 = new List<int?>(){2,3,4,6,8,9,10};
var left = from i in list1
join k in list2 on i equals k
into temp
from k in temp.DefaultIfEmpty()
select new {a = i, b = (i == k) ? k : (int?)null};
var right = from k in list2
join i in list1 on k equals i
into temp
from i in temp.DefaultIfEmpty()
select new {a = (i == k) ? i : (int?)i , b = k};
var result = left.Union(right);
If you need the ordering to be same as your example, then you will need to provide an index and order by that (then remove duplicates)
var result = left.Select((o,i) => new {o.a, o.b, i}).Union(right.Select((o, i) => new {o.a, o.b, i})).OrderBy( o => o.i);
result.Select( o => new {o.a, o.b}).Distinct();

Comparing arrays and returning a similarity figure C#

I am trying to return a number that represents the similarity between two arrays.
I.e :
Array1: {Katy, Jenny, Sarah, Ben, Jill, Tina}
Array2: {Katy, John, Sam, Ben, Jill, Linda}
I want to return the number 3 because three comparisons are correct. Is this
possible? I can't think of any functions that will do this for me.
This is how you can count the amount of items that are equal in matching indices.
var c = arr1.Where((x, i) => x.Equals(arr2[i])).Count();
Note that you might want to assure that you don't try to access arr2 in an index that is out of range:
var c = arr1.Take(arr2.Length).Count(...);
If you don't care about index positions, you should use nemesv's solution.
There are many ways to do this. Since others have already specified a few ways, I will try to post a different way of doing the same.
If you consider matching based on index, you can do something like this using Zip
var cnt = 0;
Array1.Zip(Array2,(a,b)=>{
if(a.Equals(b)) ++cnt;
return string.Empty; //we dont need this
}).Count(); // use tolist or count to force evaluation
If you don't care about ordering and are just concerned about matching, you can use Intersect
Array1.Intersect(Array2).Count()
The way I would approach this problem is too take the value in the first array and compare it with every other value in the second array. If they match than increase a compare counter and that will tell you their are three comparisons that match.
This works for me:
var array1 = new string[] {"Katy", "Jenny", "Sarah", "Ben", "Jill", "Tina"};
var array2 = new string[] {"Katy", "John", "Sam", "Ben", "Jill", "Linda"};
var similarity = (array1.Length + array2.Length) - array1.Union(array2).Count();
Edit: Oh just saw you want them to be in the same position.
You're saying "According to index", assuming you mean that if "John" is on position 1 in the first list, and on position 2 on the second list => no match.
In that case:
int maxItems = Math.Min(arr1.Length, arr2.Length);
int matchCount = 0;
for(int i = 0; i < maxItems; i++)
{
if(object.Equals(arr1[i], arr2[i]))
matchCount++;
}
I'd do it like this:
int count = array1.Zip(array2, (a, b) => a.Equals(b)).Count(b => b);
The zip part returns an IEnumerable<bool> and the count part count how many times true occurs in that list.

Categories

Resources