Let's say I have a C# variable and array:
int variable_1 = 1;
int[3] array_1 = {1,2,3};
How can I check if the value of variable_1 is equal to any of the values in array_1 without looping through array_1?
Well something has to loop. Any of the following will work:
bool exists = array.Contains(variable_1);
bool exists = Array.IndexOf(array_1, variable_1) != -1;
bool exists = Array.Exists(array_1, x => x == variable_1);
bool exists = Array.FindIndex(array_1, x => x == variable_1) != -1;
bool exists = array_1.Any(x => x == variable_1);
All of the versions using a lambda expression feel like overkill to me, but they're potentially useful if you find yourself in a situation where you don't know the actual value you're searching for - just some condition.
If you know that the array is sorted, you can use:
bool exists = Array.BinarySearch(array_1, variable_1) >= 0;
That will be O(log n) rather than O(n) (which all the others are), but it does require the array to be sorted first.
Personally I'd normally go with the very first form - assuming you're using .NET 3.5 or higher.
If you need to check for several items and the array is large, you may want to create a HashSet<int>:
HashSet<int> hashSet = new HashSet<int>(array_1);
bool exists = hashSet.Contains(variable_1);
in 3.5 and up
array_1.Contains(variable_1);
or 2.0
array_1.IndexOf(variable_1) != -1
Updated: to save on performance
mmm there can be various options,
var hasItem = Array.Exists(array_1, x => x == variable_1);
Related
I need a way to check conditions set up in runtime.
I have classes that provide conditions created by themselves.
But I don't know how to do that.
At least I want something like that:
int x = 1;
int y = 2;
int z = 3;
string s = "(x == 1 && y == 3) || z == 3";
bool b = bool.Parse(s);
I already tried stating the conditions in a string and then convert them to a bool.
Mainly I tried using this
string s = "true || false";
and then
bool b = false;
bool.TryParse(s, out b);
or
bool b = Convert.ToBoolean(s);
The "true" or "false" statements in the string are put in later.
The individual conditions are checked and being replaced with true or false.
Didn't work until now.
Edit:
I am working on a Game and there are multiple objects that act according to their individual conditions. But these conditions are set up on runtime and their length and complexity is unknown before runtime. Using strings was my first attempt because i don't know how to do this.
Also I know only a bit more than the basics so I don't know many methods and libraries.
You can try exploiting an old trick with DataTable:
using System.Data;
...
private static bool Compute(string formula, int x, int y, int z) {
using (var table = new DataTable()) {
// variables of type int
table.Columns.Add("x").DataType = typeof(int);
table.Columns.Add("y").DataType = typeof(int);
table.Columns.Add("z").DataType = typeof(int);
table.Columns.Add("result").Expression = formula;
table.Rows.Add(x, y, z);
return Convert.ToBoolean(table.Rows[0]["result"]);
}
}
...
// Please, not the syntax difference
Console.Write(Compute("(x = 1 and y = 3) or z = 3", 1, 2, 3));
You can use a C# script system like CS-Script; this allow you to execute C# as script (essentially strings). There is also the open source C# compiler Roslyn, but this may be too advanced for your needs.
I have a 2 dimensional array int[][] data and i want to see if the value contains the value 45 for example
I created this line of code
bool contains = data.Where(x => x.Contains(45)).ToArray().Count() != 0 ? true : false;
but it looks like there is unnecessary code and I am sure that there is an easier or more efficient way to do this
You could use Any linq extension.
bool exists = data.SelectMany(x=>x).Any(x=>x == 45);
Or
bool exists = data.Any(x=>x.Any(s=>s == 45));
Array.IndexOf is optimised for integer arrays, so if your inner arrays are long and you care about speeding it up that much it might be worth doing it like this:
bool exists = data.Any(a => Array.IndexOf(a, 45) != -1);
There are two issues in your code:
data is not an array of int, it is an array int[]
the ternary operator takes a bool condition and returns a value based on the bool value. So x ? true : false is the same as x. There is no need for the operator.
So what (I assume) you want is not to check if data contains 45, but if any of the arrays in data contains 45. So you either flatten the jagged array into on enumeration using SelectMany or concat two Any calls:
bool contains = data.SelectMany(d => d).Contains(45);
or
bool contains = data.Any(d => d.Contains(45);
I've been working on my own, headless browser implementation and I feel like I am making a mess of my nth-child selector logic. Given an element and it's 0-based position in its group of siblings is there a simple, one-line expression to see if that element belongs in the result set?
public bool Evaluate(HTMLElement element)
{
if (element.parentNode == element.ownerDocument)
return false;
List<Element> children = element.Parent.Children
.Where(e => e is Element)
.Cast<Element>()
.ToList();
int index = children.IndexOf(element);
bool result = (an + b test here);
return result;
}
Currently I have a convoluted set of branching logic based on tests for 0 values for (a) and (b) and I suspect I am making it more complicated than it needs to be.
If I'm understanding correctly, you need to determine whether an n exists such that index = a*n + b for some fixed a, b.
bool result = (a == 0) ? b == index : (Math.Abs(index - b) % Math.Abs(a)) == 0;
If a is 0, then index must be b. Otherwise, a must evenly divide the difference between i and b.
Naturally, if a negative value for a is not allowed you can skip the Math.Abs(a) call.
I have this function for sorting by multiple user selected columns:
public override void Sort(SortFields sortFields)
{
if (sortFields == null || sortFields.Count() == 0) return;
var res = FilteredItems.OrderBy(o => o[sortFields[0].Name], sortFields[0].Ascending ? comparer : comparerDesc);
for (int x = 1; x < sortFields.Count(); x++)
res = res.ThenBy(o => o[sortFields[x].Name], sortFields[x].Ascending ? comparer : comparerDesc);
FilteredItems = new BindingList<T>(res.ToList());
if (ListChanged != null)
ListChanged(this, new ListChangedEventArgs(ListChangedType.Reset, null));
}
The problem, of course, is that when res.ToList() is called x has been incremented to one greater than the highest index in the list and it throws an error. I know I could go ahead and do a ToList() after each sort but that defeats the purpose and isn't even guaranteed to sort correctly with all linq providers. I'm sure there's a simple solution to this... anyone want to tell me what it is? :)
It looks like you may be getting tripped up by a closure over the variable x.
That single variable is incremented on every iteration of the loop. It's incremented one last time, at which point it's 1 greater than the number of items in "sortFields", your conditional statement evaluates to False, and your for loop ends.
As user2864740 pointed out, and Eric states in his article:
Closures close over variables, not over values.
So when you then call ToList(), your chained ThenBy statements retain the final value of the variable x, which was 1 greater than the highest index.
Instead, assign the incrementer to an intermediary variable inside the loop. When you call ToList(), the final value of x won't matter.
for (int x = 1; x < sortFields.Count(); x++)
{
int y = x;
res = res.ThenBy(o => o[sortFields[y].Name], sortFields[y].Ascending ? comparer : comparerDesc);
}
Also from Eric's article, this is (hopefully) being corrected soon, though only in foreach loops apparently, not for loops:
In C# 5, the loop variable of a foreach will be logically inside the loop, and therefore closures will close over a fresh copy of the variable each time. The "for" loop will not be changed.
Try
var res = FilteredItems.OrderBy(o => o[sortFields[0].Name], sortFields[0].Ascending ? comparer : comparerDesc).ToList();
What is the best algorithm to take array like below:
A {0,1,2,3}
I expected to order it like array below:
B {3,1,0,2}
Any ideas?
So if you have two arrays and they hold the same data just in different order then just do this:
A = B
I suspect that is not your situation so I think we need more info.
What you need to do is determine the ordering of B and then apply that ordering to A. One way to accomplish this is to undo the ordering of B and keep track of what happens along the way. Then you can do the reverse to A.
Here's some sketchy C# (sorry, I haven't actually run this)...
Take a copy of B:
List<int> B2 = new List<int>(B);
Now sort it, using a sort function that records the swaps:
List<KeyValuePair<int,int>> swaps = new List<KeyValuePair<int,int>>();
B2.Sort( delegate( int x, int y ) {
if( x<y ) return -1;
if( x==y ) return 0;
// x and y must be transposed, so assume they will be:
swaps.Add( new KeyValuePair<int,int>(x,y) );
return 1;
});
Now apply the swaps, in reverse order, to A:
swaps.Reverse();
foreach( KeyValuePair<int,int> x in swaps )
{
int t = A[x.key];
A[x.key] = A[x.value];
A[x.value] = t;
}
Depending how the built-in sort algorithm works, you might need to roll your own. Something nondestructive like a merge sort should give you the correct results.
Here's my implementation of the comparer (uses LINQ, but can be easily adapted to older .net versions). You can use it for any sorting algorithms such as Array.Sort, Enumerable.OrderBy, List.Sort, etc.
var data = new[] { 1, 2, 3, 4, 5 };
var customOrder = new[] { 2, 1 };
Array.Sort(data, new CustomOrderComparer<int>(customOrder));
foreach (var v in data)
Console.Write("{0},", v);
The result is 2,1,3,4,5, - any items not listed in the customOrder are placed at the end in the default for the given type (unless a fallback comparator is given)
public class CustomOrderComparer<TValue> : IComparer<TValue>
{
private readonly IComparer<TValue> _fallbackComparer;
private const int UseDictionaryWhenBigger = 64; // todo - adjust
private readonly IList<TValue> _customOrder;
private readonly Dictionary<TValue, uint> _customOrderDict;
public CustomOrderComparer(IList<TValue> customOrder, IComparer<TValue> fallbackComparer = null)
{
if (customOrder == null) throw new ArgumentNullException("customOrder");
_fallbackComparer = fallbackComparer ?? Comparer<TValue>.Default;
if (UseDictionaryWhenBigger < customOrder.Count)
{
_customOrderDict = new Dictionary<TValue, uint>(customOrder.Count);
for (int i = 0; i < customOrder.Count; i++)
_customOrderDict.Add(customOrder[i], (uint) i);
}
else
_customOrder = customOrder;
}
#region IComparer<TValue> Members
public int Compare(TValue x, TValue y)
{
uint indX, indY;
if (_customOrderDict != null)
{
if (!_customOrderDict.TryGetValue(x, out indX)) indX = uint.MaxValue;
if (!_customOrderDict.TryGetValue(y, out indY)) indY = uint.MaxValue;
}
else
{
// (uint)-1 == uint.MaxValue
indX = (uint) _customOrder.IndexOf(x);
indY = (uint) _customOrder.IndexOf(y);
}
if (indX == uint.MaxValue && indY == uint.MaxValue)
return _fallbackComparer.Compare(x, y);
return indX.CompareTo(indY);
}
#endregion
}
In the example you gave (an array of numbers), there would be no point in re-ordering A, since you could just use B.
So, presumably these are arrays of objects which you want ordered by one of their properties.
Then, you will need a way to look up items in A based on the property in question (like a hashtable). Then you can iterate B (which is in the desired sequence), and operate on the corresponding element in A.
Both array's contain the same values (or nearly so) but I need to force them to be in the same order. For example, in array A the value "3045" is in index position 4 and in array B it is in index position 1. I want to reorder B so that the index positions of like values are the same as A.
If they are nearly the same then here is some pseudo code:
Make an ArrayList
Copy the contents of the smaller array to the arraylist
for each item I in the larger array
FInd I in the ArrayList
Append I to a new array
Remove I from the arraylist
Could the issue be resolved using a Dictionary so the elements have a relationship that isn't predicated on sort order at all?