Best way to get range from 1 to n-1 with linq - c#

I would like to use linq to query a sorted List with n elements, so that I can get elemnts between first and last.
I have tried the following, but it seems not to look good:
var result1 = myList.Skip(1).Take(myList.Count()-2);
var result2 = myList.GetRange(1, myList.Count()-2);
Are there other ways to achieve the goal?

You have to take into account that LinQ will perform as many loops as necessary to achieve its purpose. Sometimes, writing your own loop will gets better results. Then encapsulate your loop into an extension methods and you get your one line solution:
namespace System.Linq
{
public static class MyLinqExtensions
{
public static IEnumerable<T> Range<T>(this IEnumerable<T> input, int start, int end)
{
int i = 0;
foreach(var item in input)
{
if(i < start) continue;
if(i > end) break;
yield return item;
i++;
}
}
}
}

This is Best Way
var result1 = myList.Skip(1).Take(myList.Count()-2);
This Best way of Linq Query Because Getrange does not accept Negative Numer.
For Example:
MyList is No record then Skip And Take method execute Linq query out put is empty list result but Getrange method throw exception for "Non-negative number required.
Parameter name: count"

Related

adding function result to list while checking it

As I do that often enough i was wondering if there is a neat way to skip using a variable. I have a function that returns a List of unknown length. I want to add the result to another list and also know if i got returned an empty list. I could save the function result in a variable and see if its empty and otherwise add it to the list. I just was thinking if this could be done more elegantly.
I also could do:
myList.AddRange(getFiles(path));
if(getFiles(path).Count == 0)
{
doSomething();
}
getFiles being an example function that returns a list of files at a path
That way however I have to call the function twice.
This is more of a programming style question as I am quite unexperienced. Should one make a "tmp" variable everytime this happens?
Make this extension method:
public static int AddRangeEx<T>(this List<T> target, IEnumerable<T> items)
{
int result = items.Count();
if( result > 0 ) target.AddRange(items);
return result;
}
And then you'll be able to write code like this:
if(myList.AddRangeEx(getfiles(path)) > 0)
{
doSomething();
}
Alternatively, if you're concerned about side effects of the extra Count() call (even just performance side effects, but there are lots of ways to get an IEnumerable that can only run one time), you could build the extension method this way:
public static int AddRangeEx<T>(this List<T> target, IEnumerable<T> items)
{
int result = 0;
foreach (T item in items)
{
target.Add(item);
result++;
}
return result;
}
Which isn't really any different than what AddRange() and Count() were already doing.
As a bonus, you can overload the extension method for improved performance on types that already know the count:
public static int AddRangeEx<T>(this List<T> target, T[] items)
{
if (items.Length > 0)
target.AddRange(items);
return items.Length;
}
It kind of makes me sad the built-in AddRange() method doesn't already do this for us.
The first choice is to just store a local variable
var files = getFiles(path);
myList.AddRange(files);
if(files.Count == 0)
{
doSomething();
}
The second choice would be this
var count = myList.Count
myList.AddRange(getFiles(path));
if(myList.Count > count)
{
doSomething();
}

Check if list contains element that contains a string and get that element

While searching for an answer to this question, I've run into similar ones utilizing LINQ but I haven't been able to fully understand them (and thus, implement them), as I'm not familiarized with it. What I would like to, basically, is this:
Check if any element of a list contains a specific string.
If it does, get that element.
I honestly don't know how I would go about doing that. What I can come up with is this (not working, of course):
if (myList.Contains(myString))
string element = myList.ElementAt(myList.IndexOf(myString));
I know WHY it does not work:
myList.Contains() does not return true, since it will check for if a whole element of the list matches the string I specified.
myList.IndexOf() will not find an occurrence, since, as it is the case again, it will check for an element matching the string.
Still, I have no clue how to solve this problem, but I figure I'll have to use LINQ as suggested in similar questions to mine. That being said, if that's the case here, I'd like for the answerer to explain to me the use of LINQ in their example (as I said, I haven't bothered with it in my time with C#). Thank you in advance guys (and gals?).
EDIT: I have come up with a solution; just loop through the list, check if current element contains the string and then set a string equal to the current element. I'm wondering, though, is there a more efficient way than this?
string myString = "bla";
string element = "";
for (int i = 0; i < myList.Count; i++)
{
if (myList[i].Contains(myString))
element = myList[i];
}
You should be able to use Linq here:
var matchingvalues = myList
.Where(stringToCheck => stringToCheck.Contains(myString));
If you simply wish to return the first matching item:
var match = myList
.FirstOrDefault(stringToCheck => stringToCheck.Contains(myString));
if(match != null)
//Do stuff
The basic answer is: you need to iterate through loop and check any element contains the specified string.
So, let's say the code is:
foreach(string item in myList)
{
if(item.Contains(myString))
return item;
}
The equivalent, but terse, code is:
mylist.Where(x => x.Contains(myString)).FirstOrDefault();
Here, x is a parameter that acts like "item" in the above code.
string result = myList.FirstOrDefault(x => x == myString)
if(result != null)
{
//found
}
for (int i = 0; i < myList.Length; i++)
{
if (myList[i].Contains(myString)) // (you use the word "contains". either equals or indexof might be appropriate)
{
return i;
}
}
Old fashion loops are almost always the fastest.
If you want a list of strings containing your string:
var newList = myList.Where(x => x.Contains(myString)).ToList();
Another option is to use Linq FirstOrDefault
var element = myList.Where(x => x.Contains(myString)).FirstOrDefault();
Keep in mind that Contains method is case sensitive.
You could use Linq's FirstOrDefault extension method:
string element = myList.FirstOrDefault(s => s.Contains(myString));
This will return the fist element that contains the substring myString, or null if no such element is found.
If all you need is the index, use the List<T> class's FindIndex method:
int index = myList.FindIndex(s => s.Contains(myString));
This will return the the index of fist element that contains the substring myString, or -1 if no such element is found.
Many good answers here, but I use a simple one using Exists, as below:
foreach (var setting in FullList)
{
if(cleanList.Exists(x => x.ProcedureName == setting.ProcedureName))
setting.IsActive = true; // do you business logic here
else
setting.IsActive = false;
updateList.Add(setting);
}
You should be able to use something like this, it has worked okay for me:
var valuesToMatch = yourList.Where(stringCheck => stringCheck.Contains(myString));
or something like this, if you need to look where it doesn't match.
var valuesToMatch = yourList.Where(stringCheck => !stringCheck.Contains(myString));
you can use
var match=myList.Where(item=>item.Contains("Required String"));
foreach(var i in match)
{
//do something with the matched items
}
LINQ provides you with capabilities to "query" any collection of data. You can use syntax like a database query (select, where, etc) on a collection (here the collection (list) of strings).
so you are doing like "get me items from the list Where it satisfies a given condition"
inside the Where you are using a "lambda expression"
to tell briefly lambda expression is something like (input parameter => return value)
so for a parameter "item", it returns "item.Contains("required string")" . So it returns true if the item contains the string and thereby it gets selected from the list since it satisfied the condition.
To keep it simple use this;
foreach(string item in myList)//Iterate through each item.
{
if(item.Contains("Search Term")//True if the item contains search pattern.
{
return item;//Return the matched item.
}
}
Alternatively,to do this with for loop,use this;
for (int iterator = 0; iterator < myList.Count; iterator++)
{
if (myList[iterator].Contains("String Pattern"))
{
return myList[iterator];
}
}
It is possible to combine Any, Where, First and FirstOrDefault; or just place the predicate in any of those methods depending on what is needed.
You should probably avoid using First unless you want to have an exception thrown when no match is found. FirstOrDefault is usually the better option as long as you know it will return the type's default if no match is found (string's default is null, int is 0, bool is false, etc).
using System.Collections.Generic;
using System.Linq;
bool exists;
string firstMatch;
IEnumerable<string> matchingList;
var myList = new List<string>() { "foo", "bar", "foobar" };
exists = myList.Any(x => x.Contains("o"));
// exists => true
firstMatch = myList.FirstOrDefault(x => x.Contains("o"));
firstMatch = myList.First(x => x.Contains("o"));
// firstMatch => "foo"
firstMatch = myList.First(x => x.Contains("dark side"));
// throws exception because no element contains "dark side"
firstMatch = myList.FirstOrDefault(x => x.Contains("dark side"));
// firstMatch => null
matchingList = myList.Where(x => x.Contains("o"));
// matchingList => { "foo", "foobar" }
Test this code # https://rextester.com/TXDL57489
I have not seen bool option in other answers so I hope below code will help someone.
Just use Any()
string myString = "test";
bool exists = myList
.Where(w => w.COLUMN_TO_CHECK.Contains(myString)).Any();
You can check the list is empty or not in multiple ways.
1)Check list is null and then check count is greater than zero like below:-
if(myList!=null && myList.Count>0)
{
//List has more than one record.
}
2)Check list null and count greater than zero using linq query like below:-
if(myList!=null && myList.Count>0)
{
//List has more than one record.
}

How to properly check IEnumerable for existing results

What's the best practice to check if a collection has items?
Here's an example of what I have:
var terminalsToSync = TerminalAction.GetAllTerminals();
if(terminalsToSync.Any())
SyncTerminals(terminalsToSync);
else
GatewayLogAction.WriteLogInfo(Messages.NoTerminalsForSync);
The GetAllTerminals() method will execute a stored procedure and, if we return a result, (Any() is true), SyncTerminals() will loop through the elements; thus enumerating it again and executing the stored procedure for the second time.
What's the best way to avoid this?
I'd like a good solution that can be used in other cases too; possibly without converting it to List.
Thanks in advance.
I would probably use a ToArray call, and then check Length; you're going to enumerate all the results anyway so why not do it early? However, since you've said you want to avoid early realisation of the enumerable...
I'm guessing that SyncTerminals has a foreach, in which case you can write it something like this:
bool any = false;
foreach(var terminal in terminalsToSync)
{
if(!any)any = true;
//....
}
if(!any)
GatewayLogAction.WriteLogInfo(Messages.NoTerminalsForSync);
Okay, there's a redundant if after the first loop, but I'm guessing the cost of an extra few CPU cycles isn't going to matter much.
Equally, you could do the iteration the old way and use a do...while loop and GetEnumerator; taking the first iteration out of the loop; that way there are literally no wasted operations:
var enumerator = terminalsToSync.GetEnumerator();
if(enumerator.MoveNext())
{
do
{
//sync enumerator.Current
} while(enumerator.MoveNext())
}
else
GatewayLogAction.WriteLogInfo(Messages.NoTerminalsForSync);
How about this, which still defers execution, but buffers it once executed:
var terminalsToSync = TerminalAction.GetAllTerminals().Lazily();
with:
public static class LazyEnumerable {
public static IEnumerable<T> Lazily<T>(this IEnumerable<T> source) {
if (source is LazyWrapper<T>) return source;
return new LazyWrapper<T>(source);
}
class LazyWrapper<T> : IEnumerable<T> {
private IEnumerable<T> source;
private bool executed;
public LazyWrapper(IEnumerable<T> source) {
if (source == null) throw new ArgumentNullException("source");
this.source = source;
}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
public IEnumerator<T> GetEnumerator() {
if (!executed) {
executed = true;
source = source.ToList();
}
return source.GetEnumerator();
}
}
}
Personally i wouldnt use an any here, foreach will simply not loop through any items if the collection is empty, so i would just do it like that. However i would recommend that you check for null.
If you do want to pre-enumerate the set use .ToArray() eg will only enumerate once:
var terminalsToSync = TerminalAction.GetAllTerminals().ToArray();
if(terminalsToSync.Any())
SyncTerminals(terminalsToSync);
var terminalsToSync = TerminalAction.GetAllTerminals().ToList();
if(terminalsToSync.Any())
SyncTerminals(terminalsToSync);
else
GatewayLogAction.WriteLogInfo(Messages.NoTerminalsForSync);
.Length or .Count is faster since it doesn't need to go through the GetEnumerator()/MoveNext()/Dispose() required by Any()
Here's another way of approaching this problem:
int count = SyncTerminals(terminalsToSync);
if(count == 0) GatewayLogAction.WriteLogInfo(Messages.NoTerminalsForSync);
where you change SyncTerminals to do:
int count = 0;
foreach(var obj in terminalsToSync) {
count++;
// some code
}
return count;
Nice and simple.
All the caching solutions here are caching all items when the first item is being retrieved. It it really lazy if you cache each single item while the items of the list are is iterated.
The difference can be seen in this example:
public class LazyListTest
{
private int _count = 0;
public void Test()
{
var numbers = Enumerable.Range(1, 40);
var numbersQuery = numbers.Select(GetElement).ToLazyList(); // Cache lazy
var total = numbersQuery.Take(3)
.Concat(numbersQuery.Take(10))
.Concat(numbersQuery.Take(3))
.Sum();
Console.WriteLine(_count);
}
private int GetElement(int value)
{
_count++;
// Some slow stuff here...
return value * 100;
}
}
If you run the Test() method, the _count is only 10. Without caching it would be 16 and with .ToList() it would be 40!
An example of the implementation of LazyList can be found here.
If you're seeing two procedure calls for the evaluation of whatever GetAllTerminals() returns, this means that the procedure's result isn't being cached. Without knowing what data-access strategy you're using, this is quite hard to fix in a general way.
The simplest solution, as you've alluded, is to copy the result of the call before you perform any other operations. If you wanted to, you could neatly wrap this behaviour up in an IEnumerable<T> which executes the inner enumerable call just once:
public class CachedEnumerable<T> : IEnumerable<T>
{
public CachedEnumerable<T>(IEnumerable<T> enumerable)
{
result = new Lazy<List<T>>(() => enumerable.ToList());
}
private Lazy<List<T>> result;
public IEnumerator<T> GetEnumerator()
{
return this.result.Value.GetEnumerator();
}
System.Collections.IEnumerable GetEnumerator()
{
return this.GetEnumerator();
}
}
Wrap the result in an instance of this type and it will not evaluate the inner enumerable multiple times.

Is this achievable with a single LINQ query?

Suppose I have a given object of type IEnumerable<string> which is the return value of method SomeMethod(), and which contains no repeated elements. I would like to be able to "zip" the following lines in a single LINQ query:
IEnumerable<string> someList = SomeMethod();
if (someList.Contains(givenString))
{
return (someList.Where(givenString));
}
else
{
return (someList);
}
Edit: I mistakenly used Single instead of First. Corrected now.
I know I can "zip" this by using the ternary operator, but that's just not the point. I would just list to be able to achieve this with a single line. Is that possible?
This will return items with given string or all items if given is not present in the list:
someList.Where(i => i == givenString || !someList.Contains(givenString))
The nature of your desired output requires that you either make two requests for the data, like you are now, or buffer the non-matches to return if no matches are found. The later would be especially useful in cases where actually getting the data is a relatively expensive call (eg: database query or WCF service). The buffering method would look like this:
static IEnumerable<T> AllIfNone<T>(this IEnumerable<T> source,
Func<T, bool> predicate)
{
//argument checking ignored for sample purposes
var buffer = new List<T>();
bool foundFirst = false;
foreach (var item in source)
{
if (predicate(item))
{
foundFirst = true;
yield return item;
}
else if (!foundFirst)
{
buffer.Add(item);
}
}
if (!foundFirst)
{
foreach (var item in buffer)
{
yield return item;
}
}
}
The laziness of this method is either that of Where or ToList depending on if the collection contains a match or not. If it does, you should get execution similar to Where. If not, you will get roughly the execution of calling ToList (with the overhead of all the failed filter checks) and iterating the result.
What is wrong with the ternary operator?
someList.Any(s => s == givenString) ? someList.Where(s => s == givenString) : someList;
It would be better to do the Where followed by the Any but I can't think of how to one-line that.
var reducedEnumerable = someList.Where(s => s == givenString);
return reducedEnumerable.Any() ? reducedEnumerable : someList;
It is not possible to change the return type on the method, which is what you're asking. The first condition returns a string and the second condition returns a collection of strings.
Just return the IEnumerable<string> collection, and call Single on the return value like this:
string test = ReturnCollectionOfStrings().Single(x => x == "test");

How to remove elements from an array

Hi I'm working on some legacy code that goes something along the lines of
for(int i = results.Count-1; i >= 0; i--)
{
if(someCondition)
{
results.Remove(results[i]);
}
}
To me it seems like bad practice to be removing the elements while still iterating through the loop because you'll be modifying the indexes.
Is this a correct assumption?
Is there a better way of doing this? I would like to use LINQ but I'm in 2.0 Framework
The removal is actually ok since you are going downwards to zero, only the indexes that you already passed will be modified. This code actually would break for another reason: It starts with results.Count, but should start at results.Count -1 since array indexes start at 0.
for(int i = results.Count-1; i >= 0; i--)
{
if(someCondition)
{
results.RemoveAt(i);
}
}
Edit:
As was pointed out - you actually must be dealing with a List of some sort in your pseudo-code. In this case they are conceptually the same (since Lists use an Array internally) but if you use an array you have a Length property (instead of a Count property) and you can not add or remove items.
Using a list the solution above is certainly concise but might not be easy to understand for someone that has to maintain the code (i.e. especially iterating through the list backwards) - an alternative solution could be to first identify the items to remove, then in a second pass removing those items.
Just substitute MyType with the actual type you are dealing with:
List<MyType> removeItems = new List<MyType>();
foreach(MyType item in results)
{
if(someCondition)
{
removeItems.Add(item);
}
}
foreach (MyType item in removeItems)
results.Remove(item);
It doesn't seem like the Remove should work at all. The IList implementation should fail if we're dealing with a fixed-size array, see here.
That being said, if you're dealing with a resizable list (e.g. List<T>), why call Remove instead of RemoveAt? Since you're already navigating the indices in reverse, you don't need to "re-find" the item.
May I suggest a somewhat more functional alternative to your current code:
Instead of modifying the existing array one item at a time, you could derive a new one from it and then replace the whole array as an "atomic" operation once you're done:
The easy way (no LINQ, but very similar):
Predicate<T> filter = delegate(T item) { return !someCondition; };
results = Array.FindAll(results, filter);
// with LINQ, you'd have written: results = results.Where(filter);
where T is the type of the items in your results array.
A somewhat more explicit alternative:
var newResults = new List<T>();
foreach (T item in results)
{
if (!someCondition)
{
newResults.Add(item);
}
}
results = newResults.ToArray();
Usually you wouldn't remove elements as such, you would create a new array from the old without the unwanted elements.
If you do go the route of removing elements from an array/list your loop should count down rather than up. (as yours does)
a couple of options:
List<int> indexesToRemove = new List<int>();
for(int i = results.Count; i >= 0; i--)
{
if(someCondition)
{
//results.Remove(results[i]);
indexesToRemove.Add(i);
}
}
foreach(int i in indexesToRemove) {
results.Remove(results[i]);
}
or alternatively, you could make a copy of the existing list, and instead remove from the original list.
//temp is a copy of results
for(int i = temp.Count-1; i >= 0; i--)
{
if(someCondition)
{
results.Remove(results[i]);
}
}

Categories