Is there a way to optimize a foreach with LINQ? - c#

How can I check an array of integers contain an integer value.
How can i do it in LiNQ. I have to do it in LINQ Query..
Like:-
Int test = 10;
var a = from test in Test
where test.Contains(1,2,3,4,5,6,7,8,9,10)
select test.id
Currently I'm doing it through Extensions Method but the method is slow.
public static bool ContainsAnyInt(this int int_, bool checkForNotContain_, params int[] values_)
{
try
{
if (values_.Length > 0)
{
foreach (int value in values_)
{
if (value == int_)
{
if (checkForNotContain_)
return false;
else
return true;
}
}
}
}
catch (Exception ex)
{
ApplicationLog.Log("Exception: ExtensionsMerhod - ContainsAnyInt() Method ---> " + ex);
}
}
I have to do it in an optimize way because data is huge...

In most cases Linq is slower than a foreach.
You can just call the Linq Extension method:
int[] values = new[]{3,3};
bool hasValue = values.Contains(3);
It accomplishes the same thing as your extension method.

Would the following not work faster (untested):
public static bool ContainsAnyInt(this int int_, bool checkForNotContain_, params int[] values_)
{
if(values_ != null && values_.Contains(int_))
{
return !checkForNotContain_;
}
else
return false;
}

Working within your constraints, I would sort the arrays of values in each of the test classes so you could do something like:
int[] values = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var results = from test in tests
where test.BinaryContains(values)
select test.id;
And the test class would look something like:
class Test
{
public int id;
public int[] vals; //A SORTED list of integers
public bool BinaryContains(int[] values)
{
for (int i = 0; i < values.Length; i++)
if (values[i] >= vals[0] && values[i] <= vals[vals.Length])
{
//Binary search vals for values[i]
//if match found return true
}
return false;
}
}
Of course there are tons of ways you could optimize this further. If memory is not a concern, a Dictionary could give you all of the Test classes that contain a given integer.

Related

Yield return from an indexed iteration via LINQ

Leaving the performance cost of LINQ usage, I would like to know how to convert the following code into a LINQ expression
for (int i = 0; i < someArray.length(); i++)
yield return new SomeEntity(someFunction(i));
Important: I need the use of the incremented index
Update:
Rather than someArray.length(), number should be used:
for (int i = 0; i < number; i++)
yield return new SomeEntity(someFunction(i));
2nd update
I'm still getting the compilation error "not all code paths return value"
My code:
public static IEnumerable function()
{
Enumerable.Range(0,5).Select(i => new Entity());
}
3rd update
Didn't think it's relevant until I found out it's the cause for this error..
public static IEnumerable function()
{
int[] arr = { 1, 2, 3, 4 };
foreach (int i in arr)
{
Enumerable.Range(0,5).Select(i => new Entity());
}
}
If you take out the foreach 1st loop out of the equation, all replies answer to this question, but my issue is n^2.. 2 nested loops...
Any ideas?
Use the overload of Enumerable.Select that has an index into the collection:
someArray.Select((x, i) => new SomeEntity(someFunction(i)));
Edit
As you've modified your example and are not actually using a collection to iterate and index to, use Enumerable.Range:
Enumerable.Range(0, number).Select(i => new SomeEntity(someFunction(i)));
Use Enumerable.Range to generate the numbers:
Enumerable.Range(0,number).Select(i=>new SomeEntity(someFunction(i)));
Here's my LinqPad snippet.
void Main()
{
var e = SomeEntity.GetEntities(new List<int> { 1, 2, 3});
e.Dump();
}
public class SomeEntity
{
public int m_i;
public SomeEntity(int i)
{
m_i = i;
}
public override string ToString()
{
return m_i.ToString();
}
public static int someFunction(int i){ return i+100;}
public static IEnumerable<SomeEntity> GetEntities(IEnumerable<int> someArray)
{
// for (int i = 0; i < someArray.Count();i++)
// yield return new SomeEntity(someFunction(i));
// *** Equivalent linq function ***
return someArray.Select(a => new SomeEntity(someFunction(a)));
}
}

C# remove item from list of integers int[] l = {1,2,3} - or use recursion to add them

So there's this blog that gives Five programming problems every Software Engineer should be able to solve in less than 1 hour and I'm just revisiting some of the concepts.
The first question reads
Write three functions that compute the sum of the numbers in a given list using a for-loop, a while-loop, and recursion.
Obviously the for- and while-loops are easy, but i started out with
int[] l = { 1, 2, 3, 4, 5, 6, 7, 8, 9};
Is it at all possible to pop an item off the list and then pass the shortened list every time?
An attempt I saw in python:
numbers = [1,2,3,4,5,6,7,8,9]
def recurse_count(lst):
if len(lst) == 1:
return lst[0]
else:
i = len(lst) - 1
subtotal = lst[i] + lst[i - 1]
lst.pop() #into the void with you
lst[-1] = subtotal
return recurse_count(lst)
Would it be possible with a int[] in c# ?
A very elegant solution would be:
static public int sumThisUp(IEnumerable<int> list)
{
return list.FirstOrDefault() + (list.Any() ? sumThisUp(list.Skip(1)) : 0);
}
Yes. I do belive the List-class has a simple removeAt(int)-method. A recursive method would look like this:
public int sumThisUp(List<int> list) {
int result = list[0];
list.removeAt(0);
return (list.length > 0) ? result + sumThisUp(list) : result;
}
Alternatively if you dont wanna edit the orginal list this would do:
public int sumThisUp2(List<int> list, int index = 0) {
int result = list[index++];
return (list.Count > index) ? result + sumThisUp2(list, index) : result;
}
Yes, it is possible in C#.
But I want to introduce some trick first: instead of modifying the source list we can just pass the start index. It will be much faster:
private static int Sum(int[] array, int startIndex)
{
if (startIndex >= array.Length)
{
return 0;
}
return array[startIndex] + Sum(array, startIndex + 1);
}
static void Main(string[] args)
{
int[] array = new int[] { 1, 2, 3, 4 };
int result = Sum(array, 0);
Console.WriteLine(result);
}
This should do it:
public int Sum(int[] numbers, int startAt = 0)
{
if (startAt == numbers.Length)
return 0;
return numbers[startAt] + Sum(numbers, startAt + 1);
}

How to write a method using strand sort

I admit, this is a homework for my project and i came here because i don't know how to do it.
What i have to do
Write a method editUsingStrands(), which returns the growing field of integers arranged. Returned field should be the same size and with the same values ​​as stored in the specified field. The algorithm should not exceed O (n3) growth of complexity.
I have done this using LIST, but i just found out is not allowed, and so are not any complex functions like Sort, RemoveAt, Count...(dunno if all are complex functions, but i know they are not allowed).
Can somebody help me re-create it without using LIST and those functions?
Thank you very much!
My code
static int[] editUsingStrands(int[] field)
{
List<int> organizedField = new List<int>();
List<int> xField = new List<int>(field);
while(xField.Count > 0)
{
List<int> sublist = new List<int>();
sublist.Add(xField[0]);
xField.RemoveAt(0);
for(int i=0; i< xField.Count; i++)
{
if(xField[i] > sublist[sublist.Count-1])
{
sublist.Add(xField[i]);
xField.RemoveAt(i);
i--;
}
}
organizedField = new List<int>(mergeTogether(organizedField.ToArray(), sublist.ToArray()));
}
return organizedField.ToArray();
}
static int[] mergeTogether(int[] field1, int[] field2)
{
List<int> organizedMergedField = new List<int>();
int counter1 = 0, counter2 = 0;
while ((counter1 + counter2) < (field1.Length + field.Length))
{
if (field1.Length > counter1)
{
if (field2.Length > counter2)
{
if (field1[counter1] < field2[counter2])
{
organizedMergedField.Add(field1[counter1]);
counter1++;
}
else
{
organizedMergedField.Add(field2[counter2]);
counter2++;
}
}
else
{
organizedMergedField.Add(field1[counter1]);
counter1++;
}
}
else
{
organizedMergedField.Add(field2[counter2]);
counter2++;
}
}
return organizedMergedField.ToArray();
}

How to determine if three ints are all equal

Hi say I have three ints: value1, value2 and value3.
How do I best determine if they are all the same?
I tried:
return value1 == value2 == value3
But this said:
Operator '==' cannot be applied to operands of type 'bool' and 'int'.
So I guess it compares the first two which returns a boolean which it tries to compare to the third.
I could go:
return value1 == value2 && value2 == value3;
But this seems to be getting untidy.
Anybody have a good suggestion?
The second seems just fine to me.
As the list gets longer, that could get unwieldy. In which case I'd write an extension method along the lines of AllSame.
bool AllSame(this IEnumerable<int> list)
{
bool first = true;
int comparand = 0;
foreach (int i in list) {
if (first) comparand = i;
else if (i != comparand) return false;
first = false;
}
return true;
}
or use the params keyword:
bool AllSame(params int[] list)
{
return (list as IEnumerable<int>).AllSame();
}
Then you can just write:
if (AllSame(value1, value2, value3, value4, value5)) ...
That seems fine to me. The only comment I have is that you should introduce an 'explaining variable' for the equation. Besides explaining the calculation, the return now provides a nice place for a breakpoint or a tracepoint when inspecting the result.
bool allThreeAreEqual = value1 == value2 && value2 == value3;
return allThreeAreEqual;
I modified my original answer to include a method that is more general purpose and that does not rely on LINQ or extension methods. I think it's safe to assume this method would be more performant based on the fact that it doesn't have to enumerate the entire list to determine uniqueness when there are values that are different early on in the list.
class Program
{
static void Main(string[] args)
{
int value1 = 1, value2 = 2, value3 = 1;
Console.WriteLine(AllAreEqual<int>(value1, value2, value3));
Console.Write("V2: 1 value ");
Console.WriteLine(AllAreEqual_V2<int>(1));
Console.Write("V2: no value ");
Console.WriteLine(AllAreEqual_V2<int>());
Console.Write("V2: 3 values, same ");
Console.WriteLine(AllAreEqual_V2<int>(1, 1, 1));
Console.Write("V2: 3 values, different ");
Console.WriteLine(AllAreEqual_V2<int>(1, 1, 2));
Console.Write("V2: 2 values, same ");
Console.WriteLine(AllAreEqual_V2<int>(1, 1));
Console.Write("V2: 2 values, different ");
Console.WriteLine(AllAreEqual_V2<int>(1, 2));
Console.ReadKey();
}
static bool AllAreEqual<T>(params T[] args)
{
return args.Distinct().ToArray().Length == 1;
}
static bool AllAreEqual_V2<T>(params T[] args)
{
if (args.Length == 0 || args.Length == 1)
{
return true;
}
if (args.Length == 2)
{
return args[0].Equals(args[1]);
}
T first = args[0];
for (int index = 1; index < args.Length; index++)
{
if (!first.Equals(args[index]))
{
return false;
}
}
return true;
}
}
If you are just looking for elegance (Considering your already have a solution that has nothing wrong with it ) , you could go with good'ol LINQ. This can handle three or more.
class Program
{
static void Main(string[] args)
{
List<int> mylist = new List<int>();
mylist.Add(1);
mylist.Add(1);
mylist.Add(1);
mylist.Add(1);
bool allElementsAreEqual = mylist.All( x => ( x == mylist.First() ));
}
}
You can do it like this also
bool AllSame(int a, int b, int c, int comparand) {
return board[a] == comparand && board[b] == comparand && board[c] == comparand;
}
int nOneInput = 5;
int nTwoInput = 5;
int nThreeInput = 5;
if ((nOneInput + nTwoInput + nThreeInput ) / 3 == nOneInput )
{
// all 3 sides are equal when...
// the sum of all 3 divided by 3 equals one of the values
}
Using LINQ it would be best to us Any(). Why Any() instead of All() is because All() will test the predicate on all the items of the collection while Any() will exit as soon as and item match the predicate.
Here i use a reverse check. I am looking for any item that will be different than the item "a". So as soon it find one different we know they are not all equals so it exit and return true. So it will only test item "b", "c" and "d".
// all values to compare
var a = 4;
var b = 4;
var c = 4;
var d = 8;
var e = 6;
var f = 4;
// return if any of the following is different and negate to get a true
var areSame = (!new[] { b, c, d, e, f}.Any(i => i != a));
If you override equals you can create generic extensions from this that is reusable and can work for multiple type as long as they implement IEqualityComparer<T>
This is what I would do
if((value1 == value2) && (value1 == value3) && (value2 == value3))
{
//Whatever you want here
}
The accepted answer works fine, but I needed to support different types too,
so this is the generic version
public static bool AllSame<T>(params T[] items)
{
var first = true;
T comparand = default;
foreach (var i in items)
{
if (first) comparand = i;
else if (!i.Equals(comparand)) return false;
first = false;
}
return true;
}
usage:
if (AllSame(true, false, true)) // false
if (AllSame(5, 5, 5)) // true
if (AllSame(record1 , record2, record3))

Removing duplicate byte[]s from a collection

This will probably be an extremely simple question. I'm simply trying to remove duplicate byte[]s from a collection.
Since the default behaviour is to compare references, I tought that creating an IEqualityComparer would work, but it doesn't.
I've tried using a HashSet and LINQ's Distinct().
Sample code:
using System;
using System.Collections.Generic;
using System.Linq;
namespace cstest
{
class Program
{
static void Main(string[] args)
{
var l = new List<byte[]>();
l.Add(new byte[] { 5, 6, 7 });
l.Add(new byte[] { 5, 6, 7 });
Console.WriteLine(l.Distinct(new ByteArrayEqualityComparer()).Count());
Console.ReadKey();
}
}
class ByteArrayEqualityComparer : IEqualityComparer<byte[]>
{
public bool Equals(byte[] x, byte[] y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(byte[] obj)
{
return obj.GetHashCode();
}
}
}
Output:
2
The GetHashCode will be used by Distinct, and won't work "as is"; try something like:
int result = 13 * obj.Length;
for(int i = 0 ; i < obj.Length ; i++) {
result = (17 * result) + obj[i];
}
return result;
which should provide the necessary equality conditions for hash-codes.
Personally, I would also unroll the equality test for performance:
if(ReferenceEquals(x,y)) return true;
if(x == null || y == null) return false;
if(x.Length != y.Length) return false;
for(int i = 0 ; i < x.Length; i++) {
if(x[i] != y[i]) return false;
}
return true;

Categories

Resources