C# List Only Contains - c#

Was hoping to find out if there is an easy way to check if a list only contains certain list values.
For example if I have a list of int that could randomly contain distinct ints 1-10 (ie 1,3,7 or 2,3,4,6,8,9) and I want to check if the list only contains int 1 and/or 5. 1 or 5 or 1,5 would return true and anything else would return false.
This is actually for an MVC project and is a list of strings. Based on conditions I build a string list and want to check if 1 or both of 2 certain strings but no other strings are present in the list.
For now I take the list and check if it contains each of the 2 strings and removes them if they exist. I then can count the list and if > 0 I know that 1 or both of the strings are not the only values in the list. This feels very hackish and I assume there is better way to do it. Also in the future if my two strings were instead another dynamic list of strings it would be nice to have a simple method rather than having to foreach each string of both lists to remove them from one if existing in another before I can count list to get the bool I need.
Was hoping there was something similar to .Contains(T Item) like .OnlyContains(T Item or IEnumerable) but haven't found anything like that yet.
Thanks.

if (someList.Except(desiredItems).Any())
// Uh oh

If i understood the question correctly you want to know if a collection contains any of the items in another collection. Use Enumerable.Intersect:
var ints1 = new[] { 1, 3, 7 };
var ints2 = new [] { 2, 3, 4, 6, 8, 9 };
var list = new[] { 1, 5 };
bool containsAny = ints1.Intersect(list).Any();
Console.WriteLine(containsAny); // True
containsAny = ints2.Intersect(list).Any();
Console.WriteLine(containsAny); // False
To include also this requirement
A list of 1,5 or a list with no elements would also return true.
Just check if the collection contains any elements:
bool any = list.Any();

Related

How to remove an element of List<int[]> in C#

I'm trying to program a Sudoku solver in C# in which I'm using a List of an integer array with all the positions of empty fields, because I need them in my algorithm.
In the progress of solving the Sudoku I need to remove those positions which got filled with a number. But somehow my list with empty positions does not get smaller, when I use the Remove-method.
I will explain my problem with a simplified example:
List<int[]> test1 = new List<int[]>();
test1.Add(new int[] { 0, 0 });
test1.Add(new int[] { 1, 7 });
test1.Remove(new int[] { 1, 7 });
The first line generates the list with my one dimensional integer array (which always consists of two values - one for the column and one for the row-number). The empty positions get added in a method, but in this example I just added them in these two lines.
Later on in my algorithm, I want to remove elements by using the Remove-function similarly to the Add-function. It throws no errors, even while compiling. However, it's not removing anything.
I tried using the RemoveAll-method, although I don't really understand, how it works and therefore didn't find a correct solution for my problem.
By trying out a List of integers (not an integer array) the Remove-method works perfectly, but in the case of an array it doesn't seem to work this way.
Even creating a seperat variable rem
int[] rem = new int[] { 1, 7 };
test1.Remove(rem);
does not work.
I'm a beginner so I don't really know if a List of arrays is the best solution in my case.
bool IntArrayPredicate(int[] element)
{
return element.SequenceEqual(new int[] { 2, 3 });
}
List<int[]> listOfIntArray = new List<int[]>();
listOfIntArray.Add(new int[] { 0, 0 });
listOfIntArray.Add(new int[] { 1, 7 });
listOfIntArray.Add(new int[] { 2, 3 });
listOfIntArray.RemoveAll(element => element.SequenceEqual(new int[] { 1, 7 })); //It Works!. Using lambda expresion. Remove by Comparing sequences that match equals.
int[] toRemove = listOfIntArray[0];
listOfIntArray.Remove(toRemove); //It works!. Remove element by exact reference.
listOfIntArray.Remove(new int[] { 2, 3 }); // Not working / References are different.
listOfIntArray.RemoveAll(IntArrayPredicate); // It works!. Same as using lambda but using method reference.
Console.WriteLine($"{nameof(listOfIntArray)} has {listOfIntArray.Count()} elements"); // Yup. 0 elements.
The reason you're not able to remove items from your list using the Remove method is that you're storing reference types in the List, but creating new references when trying to remove an item. Because reference types by default use a reference comparison (not a comparison of their fields) to determine equality, you won't be able to remove items in that way.
One way to resolve this is to create a reference to each object in the List<int[]> outside of the list creation itself. This way, you can use the existing reference as an argument to the Remove method, and, because it's referring to the same object that was added to the list, it will match and be removed:
// Here we have 'item1' and 'item2' that refer to the location of different int[]
int[] item1 = new int[] { 0, 0 };
int[] item2 = new int[] { 1, 7 };
// And now we use those references to add the int[] items to our list
List<int[]> test1 = new List<int[]>();
test1.Add(item1);
test1.Add(item2);
// Finally, we can remove an item using the same reference that we used to add it
test1.Remove(item2);
This is very clunky, however, since we now need to maintain an individual reference for every item in our list as well as the list itself.
Another way to resolve this would be to search for the item we want to remove using our own equality algorithm (rather than relying on the default equality that Remove uses). We can use FirstOrDefault to search for the first item that has a length of 2 and whose values match those that we want. It will return a reference to the item if it's found, or null if it's not found. We can use IndexOf to get the index of the item (or -1 if it's not found), and then pass that index to the RemoveAt method to remove it:
List<int[]> test1 = new List<int[]>();
test1.Add(new int[] { 0, 0 });
test1.Add(new int[] { 1, 7 });
int indexToRemove = test1.IndexOf(test1.FirstOrDefault(item =>
item.Length == 2 && item[0] == 1 && item[1] == 7));
if (indexToRemove >= 0) test1.RemoveAt(indexToRemove);
As you can see, what you're trying to do isn't super easy. As a suggestion to help you think about the problem in a different way, you might consider using a 2-dimensional array to store the sudoku grid. Normally we store the row in the first dimesion and the column in the second dimension:
int[,] grid = new int[9, 9];
You could potentially create a few of these, one to represent the puzzle solution, one to represent the puzzle shown to the user's (with just their guesses), maybe even one to store user's "notes" (if you allow them to tag a cell with possible values before committing to a guess), though that would likely need to be a string[,] or an int[,][].
Then the typical way to loop through the grid would be something like:
for (int row = 0; row < 9; row++)
{
for (int col = 0; col < 9; col++)
{
// Do something with the cell at 'row' 'col' here
// Set a value for this cell
grid[row, col] = row + col;
// Report the value of a cell
Console.WriteLine($"The value at row {row} and column {col} is {grid[row, col]}");
}
}

I am trying to do get a list of random numbers which I want to not be repeated

I have a arraylist of names which get added 1 by 1. The range of the random number is the amount of people inside the arraylist.
For example:
NameList => [James, Vince, Joe, Joseph, John]
I want the output to be
NameListNum => [James 3, Vince 2, Joe 5, Joseph 1, John 4]
or
NameListNum => [James 2, Vince 5, Joe 1, Joseph 4, John 3]\
foreach (var name in nameList)
{
counter++;
int randomNum = rand.Next(Decimal.ToInt32(numOfShooters))+1;
nameListNum.Add(name + " "+randomNum);
foreach (var item in nameListNum)
{
}
}
Don't know if I am going in the right direction but the second foreach loop would be the one that checks the other nameListNum strings and regenerate a random number and rewrite it to the name.
Given that it is very easy to find the code to Shuffle a list of generated numbers randomly, the code is as easy as
var namesList = new []{"James", "Vince", "Joe", "Joseph", "John"};
var numsList = Enumerable.Range(1,namesList.Length).ToList().Shuffle();
var namesNumsList = namesList.Select( (n,i) => $"{n} {numsList[i]}").ToList();
Live example: https://dotnetfiddle.net/MzOwQa
If you want to randomise the names make them a List<string>:
var namesList = new List<string>{"James", "Vince", "Joe", "Joseph", "John"}.Shuffle();
The only other change is that you'll need namesList.Count on the following line in place of namesList.Length
Ok, let's go step by step. You have a list of names and you want to assign a unique random number to each name. The random numbers must be within the range [1, number of names in the list]
The naive brute force way would be to generate a random number, check if it has been rolled before and if not assign it to a name. Repeat the process for each name in the list in order and you are done.
With 4 or 5 names, this will actually run pretty fast but its wateful. Even more when lists get very big, getting to the point where its wasteful and performs horribly. Why? Well you need to roll many more times than necessary.
Is there a better way? Yes. Imagine you problem is: write a method that returns one by one random cards in a standard deck? Would you do it the same way? Or would you somehow store and ordered deck, shuffle it and then simply hand the cards out one by one?
Well, here its the same. Your standard deck is simply an ordered list of numbers from 1 to the total number of shooters: 1, 2, 3, ...., numberOfShooters.
Now, how would you shuffle it. Well, a naive way would be to create a list, then randomly pick an index, pick the number stored in that list and then remove it from the list to avoid rolling it again. That would work, but again, its wasteful. Why? Because repeatedly removing items in a list can be expensive. Remember lists are just wrappers over a standar array; removing an item mid list entails that all following numbers must be shifted un position up in the array.
An easy way to shuffle a list without all these problems is to use linq (there are better ways but this should suffice in your case):
var numbersToShuffle = Enumerable.Range(1, numberOfShooters);
var rnd = new Random();
numbersShuffled = numbersToShuffle.OrderBy(i => rnd.Next());
The rest should be easy.

NTILE function equivalent in C#

I need to implement the following SQL in C# Linq:
SELECT NTILE (3) OVER (ORDER BY TransactionCount DESC) AS A...
I couldn't find any answer to a similar problem except this. However I don't think that is what I am looking for.
I don't even know where to start, if anyone could please give me at least a starting point I'd appreciated.
-- EDIT --
Trying to explain a little better.
I have one Store X with Transactions, Items, Units and other data that I retrieve from SQL and store in a object in C#.
I have a list of all stores with the same data but in this case I retrieve it from Analysis Services due to the large amount of data retrieved (and other reasons) and I store all of it in another object in C#.
So what I need is to order the list and find out if store X is in the top quartile of that list or second or third...
I hope that helps to clarify what I am trying to achieve.
Thank you
I believe that there is no simple LINQ equivalent of NTILE(n). Anyway, depending on your needs it's not that hard to write one.
The T-SQL documentation says
Distributes the rows in an ordered partition into a specified number of groups. The groups are numbered, starting at one. For each row, NTILE returns the number of the group to which the row belongs.
(see here)
For a very crude implementation of NTILE you can use GroupBy. The following example uses an int[] for sake of simplicity, but of course you are not restricted to
int n = 4;
int[] data = { 5, 2, 8, 2, 3, 8, 3, 2, 9, 5 };
var ntile = data.OrderBy(value => value)
.Select((value,index) => new {Value = value, Index = index})
.GroupBy(c => Math.Floor(c.Index / (data.Count() / (double)n)), c => c.Value);
First, our data is ordered ascending by it's values. If you are not using simple ints this could be something like store => store.Revenue (given you'd like to get the quantiles by revenue of the stores). Futhermore we are selecting the ordered data to an anonymous type, to include the indices. This is necessary since the indices are necessary for grouping, but it seems as GroupBy does not support lambdas with indices, as Select does.
The third line is a bit less intuitive, but I'll try and explain: The NTILE function assigns groups, the rows are assigned to. To create n groups, we devide N (number of items) by n to get the items per group and then device the current index by that, to determine in which group the current item is. To get the number of groups right I had to make the number of items per group fractional and floor the calculated group number, but admittedly, this is rather empirical.
ntile will contain n groups, each one having Key equal to the group number. Each group is enumerable. If you'd like to determine, if an element is in the second quartile, you can check if groups.Where(g => g.Key == 1) contains the element.
Remarks: The method I've used to determine the group may need some fine adjustment.
You can do it using GroupBy function by grouping based on index of the object. Consider a list of integers like this:-
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8 };
You can first project the Index of all elements using Select and finally group by their resp. index. While calculating the Index we can divide it by NTILE value (3 in this case):-
var result = numbers.Select((v, i) => new { Value = v, Index = i / 3 })
.GroupBy(x => x.Index)
.Select(x => x.Select(z => z.Value).ToList());
Fiddle.

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

Binary Search on the first element in a multiple dimensional array

My goal is to perform a binary search for only the first element in a 2D array. I have been searching all day to find if it is possible using BinarySearch() in .NET but I can't find a thing.
To make this clearer. Imagine I had a 1D array, unsorted. If I sort the array, I lose the original index. I would like to create a second element of my array to hold the original index (this I can do) then sort by first element, then binary search over the first elements.
If anyone could push me in the right direction I'd be very grateful.
Thanks
Well, if I understand you correctly, you need something like this:
// initialize the array and the indexes array
var a2D = new int[2][];
a2D[0] = new[] { 3, 14, 15, 92, 65, 35 }; // <-- your array (fake data here)
a2D[1] = Enumerable.Range(0, a2D[0].Length).ToArray(); // create the indexes row
// sort the first row and the second one containing the indexes
Array.Sort(a2D[0], a2D[1]);
// now a2D array contains:
// row 0: 3, 14, 15, 35, 65, 92
// row 1: 0, 1, 2, 5, 4, 3
// and you can perform binary search on the first row:
int columnIndexOf35 = Array.BinarySearch(a2D[0], 35);
// columnIndexOf35 = 3
//
// a2D[0][columnIndexOf35] = 35 <- value
// a2D[1][columnIndexOf35] = 5 <- original index
As per MSDN, Array.BinarySearch method operates only with one-dimensional arrays, so it is impossible to use it directly in your case. Some of the options you have are:
Extract first column into a separate array and call Array.BinarySearch on it.
Define custom class Pair that implements interface IComparable and construct your array with the instances of this class.
Implement binary search on two dimensional array by yourself.
It looks like you want to have object that holds data and "original index" and than sort/search array of objects by data.
(This answer shows Andrei's option 2)
class IndexedData:IComparable
{
public MyType Data;
public int OriginalIndex;
public int CompareTo(object obj) {
// add correct checks for null,.. here
// and return correct comparison result.
// I.e. if MyType is IComparable - just delegate.
return Data.CompareTo(obj);
}
Check IComparable on MSDN for implementation/usage details.
Depending on what you're planning to do with the arrays afterwards, another solution might be to use LINQ.
var unsortedStartingArray = new[] {3, 6, 2, 1, 20, 20};
var q = unsortedStartingArray
.Select((item, index) => new {item, index})
.ToLookup(x => x.item, x => x.index);
var notFound = q[30]; // An empty array. Nothing found
var indexOf1 = q[1].First(); // returns 3
var multipleIndexsOf20 = q[20]; // Returns an array with 4, 5
The index into the lookup would then be the value you're searching for. Performance wise I would guesstimate this to be faster aswell about 5 times slower from my crude testing.

Categories

Resources