I have if statement like this:
if (myList.Any(x => s.Contains(x))
{
//some code here
}
in which I check if there is a string in myList which is contained in a string s.
Is it somehow possible to get the element x of this list and use it in the if statement showed above (in "//some code here" part), when the condition is met?
Thank you.
Switch from Any to FirstOrDefault, that will return the item that matched the test or null if no item was matched.
var found = myList.FirstOrDefault(x => s.Contains(x));
if (found != null)
{
//some code here
}
If null could be considered a "valid value" for a element in myList you can create a extension method TryFirst
public static class ExtensionMethods
{
public static bool TryFirst<T>(this IEnumerable<T> #this, Func<T, bool> predicate, out T result)
{
foreach (var item in #this)
{
if (predicate(item))
{
result = item;
return true;
}
}
result = default(T);
return false;
}
}
This would let you do
string foundString;
var wasFound = myList.TryFirst(x => s.Contains(x), out foundString);
if (wasFound)
{
//some code here
}
and tell the difference between a null in your list and a default result.
The above two methods only act on the first item on the list that the Contains will match, if you want to act on all the items use a Where( clause and a foreach
foreach(var item in myList.Where(x => s.Contains(x))
{
//some code here
}
You must promise you will not use the following code and use one of the other options first
You can also do your stated question, it is possible to get a variable assigned to inside lambada. However this can not be done with expression lambadas, only with statement lambadas.
string matachedString = null;
if (myList.Any(x => { var found = s.Contains(x);
if(found)
matachedString = x;
return found;
});
{
//some code here
}
But only do this option as a last resort, use one of the more appropriate methods like FirstOrDefaut or write a custom method like TryFirst first.
I'd use foreach/Where()for this, even if I'm only expecting 0 or 1 result:
foreach (var item in myList.Where(x => s.Contains(x)))
{
//some code here
}
Related
I have following extension function:
public static IEnumerable<T> Select<T>(this IDataReader reader,
Func<IDataReader, T> selector)
{
while (reader.Read())
{
yield return selector(reader);
}
}
which is being used like:
var readFields = dsReader.Select(r =>
{
var serviceResponse = myService.Decrypt<DateTime>(r.GetString(DATE_VALUE), r.GetInt32(DEK_ID));
if (serviceResponse.IsSuccessful)
{
return new DataField<DateFieldValue>
{
FieldValue = new DateFieldValue { Data = serviceResponse.Value }
};
}
return null;
});
if (!readFields.IsCollectionNullOrEmpty())
returnFinalFields.AddRange(readFields);
The problem I am facing here is that even if serviceResponse.IsSuccessful is false the readFields is not empty it contains an enumerable with an item that is null. Is there a way we can return an empty collection here?
The real problem here is that you don't want to be selecting out a null value when the service doesn't have a successful response. You'll want to filter out the successful responses as a part of your query:
var readFields = from r in dsReader
let serviceResponse = myService.Decrypt<DateTime>(r.GetString(DATE_VALUE), r.GetInt32(DEK_ID))
where serviceResponse.IsSuccessful
select new DataField<DateFieldValue>
{
FieldValue = new DateFieldValue { Data = serviceResponse.Value }
};
The Select method could check the returned result and only yield it's value when valid. For example not null:
public static IEnumerable<T> Select<T>(this IDataReader reader, Func<IDataReader, T> selector)
where T:class
{
while (reader.Read())
{
var res = selector(reader);
if(res!=null)
yield return res;
}
}
Although as stated by Servy, that would normally not belong in a regular Select. The method could be called something like SelectValidValues to avoid confusion.
Another way would be to have the lambda parameter return a Tuple containing both the result and if it's valid.
Yet another way is to have an optional parameter (as a value or an extra predicate function) that checks which values are valid
Interesting (mis?) use of Select. Your issue is you return a null from the Select delegate when IsSuccessful is false. Since not returning a value from Select's delegate isn't an option, filter afterwards:
var readFields = dsReader.Select(r => {
var serviceResponse = myService.Decrypt<DateTime>(r.GetString(DATE_VALUE), r.GetInt32(DEK_ID));
if (serviceResponse.IsSuccessful)
return new DataField<DateFieldValue> {
FieldValue = new DateFieldValue { Data = serviceResponse.Value }
};
else
return null;
}).Where(df => df != null);
I have the following code
var filteredList = posData.Where(x => MyFilter(x, ruleDetail.wheres)).ToList();
where MyFilter is defined as
static bool MyFilter(Dictionary<string,string> dict, List<WhereClause> wheres)
{
if (dict["x"] == "y")
return true;
else
return false;
}
posData is of type
List<dictionary<string,string>>
I have a breakpoint in MyFilter function but the code execution never gets there. I am looking for MyFilter to do some custom analysis based on the wheres parameter. This is only a small part of the code. Please help me figure out why is MyFilter not getting called ?
Your code should work fine and as expected. The only reason that it wouldn't work in your case is if posData is empty, so make sure that it's not.
I tried it with this code (which is basically the same as yours):
static void Main()
{
// create test collection
var posData = new List<Dictionary<string,string>>();
var test = new Dictionary<string,string>();
test.Add("x", "y");
posData.Add(test);
// call the Where function
var filteredList = posData.Where(x => MyFilter(x)).ToList();
Console.WriteLine(filteredList.Count); // outputs "1"
}
static bool MyFilter(Dictionary<string,string> dict)
{
Console.WriteLine("hello"); // outputs "hello"
return dict["x"] == "y";
}
I am trying to use SelectMany to compile a list of lists, however the selector may encounter an error and therefore have no results.
I'm going to provide the actual function I'm trying to write and then the snippet I wrote to further explore it.
In the production code, my goal is to handle the case that the serializer throws an exception.
In the sample code I have solved the problem for the case of strings, but am not sure if this solution is really more than a hack.
Production Code:
public List<click> Clicks(int advertiserId, DateTime date)
{
var dirInfo = new DirectoryInfo(DirName(date, advertiserId));
if (dirInfo.Exists)
{
var files = dirInfo.EnumerateFiles();
var clicks = files.SelectMany(c =>
{
using (var stream = c.OpenRead())
{
return (click[])clicksSerializer.Deserialize(stream);
}
});
return clicks.ToList();
}
return null;
}
Sample Code:
void Main()
{
var ids = new [] { 1, 2, 3 };
var names = ids.SelectMany(id =>
{
try
{
return GetNames(id);
}
catch
{
Console.WriteLine ("Error getting names for {0}", id);
// RESULT: NullReferenceException at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()
//return null;
// RESULT: an empty string in the result, but how to this with other types?
return new string [] { string.Empty };
}
});
foreach (var name in names)
{
Console.WriteLine ("Name: {0}", name);
}
}
string[] GetNames(int id)
{
switch (id)
{
case 1:
return new [] {"Jim", "Bob"};
case 2:
return new [] {"Harry", "Larry"};
default:
throw new Exception("invalid id");
}
}
Yes, returning an empty sequence is entirely valid, although I'd use
return Enumerable.Empty<string>();
instead to be clearer.
SelectMany - in the form you've used - really does just flatten a sequence of sequences, and if some of those intermediate sequences are empty, they'll just contribute nothing to the overall sequence. No problem in that at all.
You could return default(T) for some other type T although I'm not sure how useful that would be:
public static IEnumerable<T> TrySelectMany<T>(this IEnumerable<T> seq, Func<T, IEnumerable<T>> selector)
{
return seq.SelectMany(i => {
try {
return selector(i);
}
catch(Exception) {
return new T[] { default(T) };
}
});
}
I would consider returning Enumerable.Empty<T>() instead in the catch block.
I have following method. I need to return var tynames by method so what would be the return type of the method will it be List<string> or something else and also what is the use of FirstOrDefault().
Thanks in advance for your reply
public static List<string> AppType()
{
var context = new Dll_IssueTracking.IssuTrackingEntities();// Object context defined in Dll_IssuTracking DLL
var query = from c in context.ApplicationTypes//Query to find TypeNames
select new { c.TypeName };
var **TypeNames** = query.FirstOrDefault();
}
FirstOrDefault returns the first element found, or the default value (which is null in this case) if the query returned no results.
In this case the return value of the method should be ApplicationType:
public static ApplicationType AppType()
{
var context = new Dll_IssueTracking.IssuTrackingEntities(); // Object context defined in Dll_IssuTracking DLL
var query = from c in context.ApplicationTypes //Query to find TypeNames
select new { c.TypeName };
return query.FirstOrDefault();
}
FirstOrDefault return first element in sequence, in this sample ApplicationTypes is your sequence or a default value if the sequence contains no elements.
FirstOrDefault is an extension method which looks something like this:
public T FirstOrDefault>T>(this IEnumerable<T> query)
{
return query.Any() ? query.First() : default(T);
}
So, it returns the first element in the sequence if it is not empty, or the default of the type if the sequence is empty.
For Instance, if you have an Enumerable<LinqEntity>, then most likely default(LinqEntity) is null. If you had something like Enumerable<int> then default(int) is 0.
I have a method that is supposed to check whether there is exactly one element in a collection that holds true for some predicate (given as a Func).
public bool ExistsUnique(Func<T, bool> p)
{
var tempCol = from i in MyCollection where p(i) select i;
return (tempCol.Count() == 1);
}
The problem with this is that when a second element that also holds true for the predicate
is found (for example two of the same string exists in a collection) the count is still 1. Which means it either overrides the first element or never adds the second because it already exists.
Any ideas as to how I can fix this method?
thx
/Peter
You can use the Single() method provided by LINQ like this:
public bool ExistsUnique(Func<T, bool> p)
{
try
{
var temp = myCollection.Single(x => p(x));
}
catch(Exception e)
{
// log exception
return false;
}
return true;
}
"Returns the only element of a sequence that satisfies a specified condition, and throws
an exception if more than one such element exists."
From http://msdn.microsoft.com/en-us/library/bb535118.aspx
EDIT
To avoid throwing an exception, you may also use the SingleOrDefault() method:
public bool ExistsUnique(Func<T, bool> p)
{
return myCollection.SingleOrDefault(x => p(x)) != null;
}
There must be some other problem. I'd suspect your predicate. For example, this returns a count of 2, as expected:
List<string> MyCollection = new List<string>()
{
"hello",
"hello"
};
var tempCol = from i in MyCollection where i == "hello" select i;
int count = tempCol.Count();
I doubt that it's the way you're calling it, either. The following works (returns false):
static List<string> MyCollection = new List<string>()
{
"hello",
"hello"
};
static bool ExistsUnique(Func<string, bool> p)
{
var tempCol = from i in MyCollection where p(i) select i;
return tempCol.Count() == 1;
}
static void DoIt()
{
bool isUnique = ExistsUnique((s) => s.Equals("hello"));
Console.WriteLine(isUnique);
}
Are you sure tempCol has looped completely through MyCollection?
is Count() a method that forces the complete loop or is it lazy?
Does for example tempCol.ToList().Count give the correct result?
This implementation would make it so you don't have to actually enumerate the entire collection, so will save you some execution time.
public bool ExistsUnique(Func<T, bool> p)
{
return MyCollection.Where(i => p(i)).Take(2).Count() == 1;
}
The Take(2) limits the Count to only enumerate the first two meeting the criteria.