How use contains with two dimenzional list - c#

How find if any list in list of list contains all elements in another list?
Something like list list .contains(list), where list(list) is stanjaDKA, and list is tmpzaNormalanPrijelaz, and all list members are of type int?
I tried this but I get to much states in stanjaDKA at the end.
int indeks=stanjaDKA.FindIndex(x=>x.Equals(tmpzaNormalanPrijelaz));
if (indeks==-1 && tmpzaNormalanPrijelaz.Count>0)
{
stanjaDKA.Add(tmpzaNormalanPrijelaz);
}

How find if any X in list of X
Use LINQ's Any:
bool anyXInListOfX = myListOfX(x => someConditionOnX);
list contains all elements in another list
If you're not concerned about duplicate elements (i.e. if you're happy that {1} contains all the elements in {1, 1}), you can use LINQ's Except and check there is nothing left:
bool firstListContainsAllElementsInSecondList =
!mySecondList.Except(myFirstList).Any();
However, "any list contains all elements" is equivalent to "all lists don't contain all elements", and the don't cancels with the ! in the above, so in your case I'd do something like
if (stanjaDKA.All(l => tmpzaNormalanPrijelaz.Except(l).Any()))
{
stanjaDKA.Add(tmpzaNormalanPrijelaz);
}
This reads as "if all the lists in stanjaDKA are each missing at least one element in tmpzaNormalanPrijelaz, add tmpzaNormalanPrijelaz to stanjaDKA".

depending on what you are really want this will help you to do the mayor stuff
// Sample List<List<int>>
var listList = new List<List<int>>();
listList.Add(new List<int>() { 0, 1, 2, 3, 4 });
listList.Add(new List<int>() { 0, 1, 2, 3, 4 });
listList.Add(new List<int>() { 1, 1, 2, 3, 4 });
listList.Add(new List<int>() { 1, 1, 1, 1, 1 });
listList.Add(new List<int>() { 5, 6, 7, 8, 9 });
// the List you are seaching for
var searchList = new List<int>() { 10 };
foreach(List<int> list in listList)
{
var newList =list.Intersect(searchList);
if (newList.Count() == searchList.Count)
{
string elements = "";
foreach (int item in newList)
{
elements += item + " ";
}
Console.WriteLine(elements);
}
}
Console.ReadLine();
you should also take a look at this Link maybe you need it

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.

Remove the end of a list based on the start of another list

I have two lists:
var list1 = new List<int> { 0, 1, 2 };
var list2 = new List<int> { 1, 2, 3 };
I want to be able to check if the ending chunk of list1 is present at the start of list2. After that I want to delete one of the chunks from any of the lists, merging both into a third list (sequentially, list1 + list2).
var list3 = list1.Something(list2);
//Returns 0,1,2,3 instead of 0,1,2,1,2,3
There's another problem, one list can be smaller than the other, such as:
0,1,2,3 <-- 2,3,4 = 0,1,2,3,4
5,6 <-- 6,7,8 = 5,6,7,8
And of course, both lists can be different:
0,1,2 <-- 5,6,7 = 0,1,2,5,6,7
[empty] <-- 1,2 = 1,2
Is there any method provided by .Net Framework that allows me to do that?
If not, could you help me create one?
The end and start can only "kill" each other if they are sequentially equal.
Example, if list1 ends in 1,2 and list2 starts with 2,1 they are not equal.
So, Distinct() is not helpful.
My use case:
private List<int> Cut(this List<int> first, List<int> second)
{
//Code
return new List<int>();
}
internal List<int> MergeKeyList()
{
var keyList = new List<int>() {0, 1, 2};
var newList = new List<int>() {1, 2, 3};
return keyList.InsertRange(keyList.Count, keyList.Cut(newList));
}
Would be much more efficient with for loops .. but whatever:
keyList.TakeWhile((_, i) => !keyList.Skip(i).SequenceEqual(newList.Take(keyList.Count - i)))
.Concat(newList)
Try this:
void Main()
{
var keyList = new List<int>() {0, 1, 2};
var newList = new List<int>() {1, 2, 3};
var result = keyList.Cut(newList);
}
public static class Ex
{
public static List<int> Cut(this List<int> first, List<int> second)
{
var skip =
second
.Select((x, n) => new { x, n })
.Where(xn => xn.x == first.Last())
.Where(xn =>
first
.Skip(first.Count - xn.n - 1)
.SequenceEqual(second.Take(xn.n + 1)))
.Reverse()
.Select(xn => xn.n + 1)
.FirstOrDefault();
return first.Concat(second.Skip(skip)).ToList();
}
}
result becomes:
Also:
{ 0, 1, 2 } & { 1, 2, 1, 2, 3 } => { 0, 1, 2, 1, 2, 3 }
{ 0, 1, 2, 1 } & { 1, 2, 1, 2, 3 } => { 0, 1, 2, 1, 2, 3 }

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 distinct list between two lists in C#

I have two lists of strings. How do I get the list of distinct values between them or remove the second list elements from the first list?
List<string> list1 = { "see","you","live"}
List<string> list2 = { "see"}
The result should be {"you","live"}.
It looks to me like you need Enumerable.Except():
var differences = list1.Except(list2);
And then you can loop through the differences:
foreach(var difference in differences)
{
// work with each individual string here.
}
If you want to get items from the first list except items in the second list, use
list1.Except(list2)
If you want to get items that are in the first list or in the second list, but not both, you can use
list1.Except(list2).Concat(list2.Except(list1))
This is the good way I find unique....
Unique from two list
var A = new List<int>() { 1,2,3,4 };
var B = new List<int>() { 1, 5, 6, 7 };
var a= A.Except(B).ToList();
// outputs List<int>(2) { 2,3,4 }
var b= B.Except(A).ToList();
// outputs List<int>(2) { 5,6,7 }
var abint= B.Intersect(A).ToList();
// outputs List<int>(2) { 1 }
here is my answer,
find distinct value's in two int list and assign that vlaues to the third int list.
List<int> list1 = new List <int>() { 1, 2, 3, 4, 5, 6 };
List<int> list2 = new List<int>() { 1, 2, 3, 7, 8, 9 };
List<int> list3 = new List<int>();
var DifferentList1 = list1.Except(list2).Concat(list2.Except(list1));
foreach (var item in DifferentList1)
{
list3.Add(item);
}
foreach (var item in list3)
{
Console.WriteLine("Different Item found in lists are{0}",item);
}
Console.ReadLine();

LINQ for diffing sets

I have the following arrays:
var original= new int[] { 2, 1, 3 };
var target = new int[] { 1, 3, 4 };
enum Operation {Added,Removed}
I would like to execute a LINQ query that would return the following:
{{2,Removed},{4,Added}}
Limitation: I would like LINQ to perform this very efficiently and avoid and O(n^2) style algorithms.
Perhaps a LINQ solution is not the best option in this case.
This will produce a dictionary with the result that you want.
Dictionary<int, Operation> difference = new Dictionary<int,Operation>();
foreach (int value in original) {
difference.Add(value, Operation.Removed);
}
foreach (int value in target) {
if (difference.ContainsKey(value)) {
difference.Remove(value);
} else {
difference.Add(value, Operation.Added);
}
}
To keep the size of the dictionary down, perhaps it's possible to loop the enumerations in parallell. I'll have a look at that...
Edit:
Here it is:
Dictionary<int, Operation> difference = new Dictionary<int,Operation>();
IEnumerator<int> o = ((IEnumerable<int>)original).GetEnumerator();
IEnumerator<int> t = ((IEnumerable<int>)target).GetEnumerator();
bool oActive=true, tActive=true;
while (oActive || tActive) {
if (oActive && (oActive = o.MoveNext())) {
if (difference.ContainsKey(o.Current)) {
difference.Remove(o.Current);
} else {
difference.Add(o.Current, Operation.Removed);
}
}
if (tActive && (tActive = t.MoveNext())) {
if (difference.ContainsKey(t.Current)) {
difference.Remove(t.Current);
} else {
difference.Add(t.Current, Operation.Added);
}
}
}
Edit2:
I did some performance testing. The first version runs 10%-20% faster, both with sorted lists and randomly ordered lists.
I made lists with numbers from 1 to 100000, randomly skipping 10% of the numbers. On my machine the first version of the code matches the lists in about 16 ms.
enum Operation { Added, Removed, }
static void Main(string[] args)
{
var original = new int[] { 2, 1, 3 };
var target = new int[] { 1, 3, 4 };
var result = original.Except(target)
.Select(i => new { Value = i, Operation = Operation.Removed, })
.Concat(
target.Except(original)
.Select(i => new { Value = i, Operation = Operation.Added, })
);
foreach (var item in result)
Console.WriteLine("{0}, {1}", item.Value, item.Operation);
}
I don't think you can do this with LINQ using only a single pass given the stock LINQ extension methods but but might be able to code a custom extension method that will. Your trade off will likely be the loss of deferred execution. It would be interesting to compare the relative performance of both.
You are out of luck. If, as you stated in the comments, the lists are not sorted you can't compute the difference you seek in a single forward pass. Consider:
{ 1, 2, 3, 4, 5, 6, 7, ...
{ 1, 2, 3, 6, 7, 8, 9, ...
At the point where the first difference in encountered (4 vs. 6) it's impossible for you to determine if you are looking at the removal of 4 & 5 (as would be the case if both lists were monotonically increasing, or the insertion of 6, 7, 8, & 9 as would be the case if the lists continued like so:
{ 1, 2, 3, 4, 5, 6, 7, 8, 9,...
{ 1, 2, 3, 6, 7, 8, 9, 4, 5, 6, 7, 8, 9,...
This will achieve the result in a single pass, however I'm not sure of the complexity of the GroupBy operation.
var original= new int[] { 1, 2, 3 };
var target = new int[] { 1, 3, 4 };
var output = original.Select( i => new { I = i, L = "o" } )
.Concat( target.Select( i => new { I = i, L = "t" } ) )
.GroupBy( i => i.I ).Where( i => i.Count() == 1 )
.Select( i => new { I = i.Key, S = (i.ElementAt( 0 ).L == "o" ? Operation.Removed : Operation.Added) } );

Categories

Resources