LINQ generic function for find in a enumerable - c#

I need to create a method that with a generic enumerable of type T it finds inside it using in the where the term i specify
public static object findInList<T>(T[] list, string searchTerm, string seachIndex)
{
string normalized1 = Regex.Replace(seachIndex, #"\s", "");
var sel = (from l in list
where normalized1.Equals([the item i want to compare])
select l).FirstOrDefault();
return sel ;
}
i need this because i want to create a generic method for search an item in my array that i can customize in some way (below the code in its original way)
[...]
string normalized1 = Regex.Replace(seachIndex, #"\s", "");
sel = (from l in list
where normalized1.Equals(l.Ordine)
select l).FirstOrDefault();
[...]
[edit]
Thanks to Servy for the answer. For full index of this answer i add here how to call this method
Func<XXX, string> keySelector = delegate(XXX b) { return b.XX; };
var return = findInList<XXX>(list, keySelector, seachIndex);
Where XXX is the type of the list and XX is the property you want to compare for the search

What you need here is for your method to accept a selector, some function that determines what you should compare for each of your objects.
public static T findInList<T>(
IEnumerable<T> sequence,
Func<T, string> keySelector,
string searchTerm,
string seachIndex)
{
string normalized1 = Regex.Replace(seachIndex, #"\s", "");
return (from l in sequence
where normalized1.Equals(keySelector(l))
select l).FirstOrDefault();
}
You can also return a T instead of an object, since you know that that's what it is, ensuring that the caller doesn't need to cast it back to what it is. You can accept an IEnumerable instead of an array since you're only ever iterating it, thus giving the caller more flexibility while still letting you do everything that you need to do.

Related

Get last duplicate element in a list

I have a list contains duplicate items.
List<string> filterList = new List<string>()
{
"postpone", "access", "success", "postpone", "success"
};
I get the output which is postpone, access, success by using
List<string> filter = filterList.Distinct().ToList();
string a = string.Join(",", filter.Select(a => a).ToArray());
Console.WriteLine(a);
I had saw other example, they can use groupby to get the latest element since they have other item like ID etc. Now I only have the string, how can I get the latest item in the list which is access, postpone, success? Any suggestion?
One way to do this would be use the Index of the item in original collection along with GroupBy. For example,
var lastDistinct = filterList.Select((x,index)=> new {Value=x,Index=index})
.GroupBy(x=>x.Value)
.Select(x=> x.Last())
.OrderBy(x=>x.Index)
.Select(x=>x.Value);
var result = string.Join(",",lastDistinct);
Output
access,postpone,success
An OrderedDictionary does this. All you have to do is add your items to it with a logic of "if it's in the dictionary, remove it. add it". OrderedDictionary preserves the order of adding so by removing an earlier added one and re-adding it it jumps to the end of the dictionary
var d = new OrderedDictionary();
filterList.ForEach(x => { if(d.Contains(x)) d.Remove(x); d[x] = null; });
Your d.Keys is now a list of strings
access
postpone
success
OrderedDictionary is in the Collections.Specialized namespace
If you wanted the keys as a CSV, you can use Cast to turn them from object to string
var s = string.Join(",", d.Keys.Cast<string>());
Your input list is only of type string, so using groupBy doesn't really add anything. If you consider your code, your first line gives you the distinct list, you only lose the distinct items because you did a string.join on line 2. All you need to do is add a line before you join:
List<string> filter = filterList.Distinct().ToList();
string last = filter.LastOrDefault();
string a = string.Join(",", filter.Select(a => a).ToArray());
Console.WriteLine(a);
I suppose you could make your code more terse because you need neither .Select(a => a) nor .ToArray() in your call to string.Join.
GroupBy would be used if you had a list of class/struct/record/tuple items, where you might want to group by a specific key (or keys) rather than using Distinct() on the whole thing. GroupBy is very useful and you should learn that, and also the ToDictionary and ToLookup LINQ helper functionality.
So why shouldn't you return the first occurrence of "postpone"? Because later in the sequence you see the same word "postpone" again. Why would you return the first occurrence of "access"? Because later in the sequence you don't see this word anymore.
So: return a word if the rest of the sequence does not have this word.
This would be easy in LINQ, with recursion, but it is not very efficient: for every word you would have to check the rest of the sequence to see if the word is in the rest.
It would be way more efficient to remember the highest index on which you found a word.
As an extension method. If you are not familiar with extension methods, see extension methods demystified.
private static IEnumerable<T> FindLastOccurences<T>(this IEnumerable<T> source)
{
return FindLastOccurrences<T>(source, null);
}
private static IEnumerable<T> FindLastOccurences<T>(this IEnumerable<T> source,
IEqualityComparer<T> comparer)
{
// TODO: check source not null
if (comparer == null) comparer = EqualityComparer<T>.Default;
Dictionary<T, int> dictionary = new Dictionary<T, int>(comparer);
int index = 0;
foreach (T item in source)
{
// did we already see this T? = is this in the dictionary
if (dictionary.TryGetValue(item, out int highestIndex))
{
// we already saw it at index highestIndex.
dictionary[item] = index;
}
else
{
// it is not in the dictionary, we never saw this item.
dictionary.Add(item, index);
}
++index;
}
// return the keys after sorting by value (which contains the highest index)
return dictionay.OrderBy(keyValuePair => keyValuePair.Value)
.Select(keyValuePair => keyValuePair.Key);
}
So for every item in the source sequence, we check if it is in the dictionary. If not, we add the item as key to the dictionary. The value is the index.
If it is already in the dictionary, then the value was the highest index of where we found this item before. Apparently the current index is higher, so we replace the value in the dictionary.
Finally we order the key value pairs in the dictionary by ascending value, and return only the keys.

How to return a read-only IEnumerable<T> instead of a List<T>

i wanted to integrate ienumerable in my code so that it is readonly but i don't know where to possibly implement it. So far i haven't found any solution in the internet that might answer my problem. As of now, i have only used List and wanted to integrate ienumerable in my code. Also, feel free to suggest anything if you notice bad coding practices.
Here is the code:
public static List<GuitarItems> GetGuitarItems(string itemCategory)
{
List<GuitarItems> list = new List<GuitarItems>();
string query = string.Format("SELECT * FROM guitarItems WHERE brand LIKE #brand");
try
{
conn1.Open();
command1.CommandText = query;
command1.Parameters.Add(new SqlParameter("brand", itemCategory));
SqlDataReader reader = command1.ExecuteReader();
while (reader.Read())
{
int id = reader.GetInt32(0);
string type = reader.GetString(1);
string brand = reader.GetString(2);
string model = reader.GetString(3);
double price = reader.GetDouble(4);
string itemimage1 = reader.GetString(5);
string itemimage2 = reader.GetString(6);
string description = reader.GetString(7);
string necktype = reader.GetString(8);
string body = reader.GetString(9);
string fretboard = reader.GetString(10);
string fret = reader.GetString(11);
string bridge = reader.GetString(12);
string neckpickup = reader.GetString(13);
string bridgepickup = reader.GetString(14);
string hardwarecolor = reader.GetString(15);
GuitarItems gItems = new GuitarItems(id, type, brand, model, price, itemimage1, itemimage2, description, necktype, body,
fretboard, fret, bridge, neckpickup, bridgepickup, hardwarecolor);
list.Add(gItems);
}
}
finally
{
conn1.Close();
command1.Parameters.Clear();
}
return list;
}
And then here is another code:
private void FillPage()
{
List<GuitarItems> itemList = new List<GuitarItems>();
List<string> itemListPage = new List<string>();
itemList = ConnectionClassGuitarItems.GetGuitarItems(brandType);
StringBuilder sb = new StringBuilder();
foreach (GuitarItems gList in itemList)
{
itemListPage.Add("GuitarItemsIbanezDetails" + (x + 1) + ".aspx");
sb.Append(
string.Format(
#"
<div class='one-two'>
<img runat="'server'" src='{0}'/>
<div class='content'>
<div id='label'>{1} {2}</div>
</div>
</div>", gList.ItemImage1, gList.Brand, gList.Model, itemListPage[x]));
x++;
}
lblOutput.Text = sb.ToString();
}
Technically a List<T> is an IEnumerable<T>, but I understand what you mean. If you return a List<T> then that list may be modified. You want to return something that can get passed around without anyone modifying its contents.
There are two things you can do to achieve this. The first may be all you need.
First, change this
public static List<GuitarItems> GetGuitarItems(string itemCategory)
to this:
public static IReadOnlyList<GuitarItems> GetGuitarItems(string itemCategory)
If you do that and nothing else, the return value of the function will be cast as IReadOnlyList<T>. That interface doesn't allow modification of the list. (It doesn't prevent altering the properties of items in the list - that's an entirely separate matter.)
List<T> can be cast as IReadOnlyList<T> so you don't have to change anything else inside your method. You can create a List<GuitarItems> just as you are now, but return it as an IReadOnlyList<GuitarItems> just by changing the return type of the function.
That probably accomplishes what you need. However, if you're especially concerned about something else modifying the contents of that list you can go further.
For example, even though the item returned from the collection is cast as IReadOnlyList<GuitarItems>, someone could still do this:
var readonlyList = GetGuitarItems("category"); // returns IReadOnlyList<GuitarItems>
var list = readonlyList as List<GuitarItems>;
list.Clear(); // Oh, no - they've modified the list anyway!
This will work because the item returned from the function is actually a List. No one should try to cast it as something else - they should use the type you're returning. But for some odd reason someone could do that.
For extra prevention you could change the return of your function from this:
return list;
To this:
return list.AsReadOnly();
The result is that now you're not returning a List<GuitarItems> cast as IReadOnlyList<GuitarItems>. AsReadOnly() creates a new collection, a ReadOnlyCollection<GuitarItems> and casts that as IReadOnlyList<GuitarItems>. Now not only does the type getting returned indicate that the list can't be modified, but it really can't be modified because it's a read-only collection.
A good way to look at it is that the return value of the method should indicate what you expect consumers to do with it. If you want them to receive a list that they shouldn't modify then return an IReadOnlyList<T>.
A related question is whether you should return an IEnumerable<T> or an IReadOnlyList<T>. IEnumerable<T> is more general and also does not represent a list that can be changed. You'll see it used far more often. The difference is that an IEnumerable<T> could represent a query that gets executed. If the items to be enumerated get enumerated more than once then it could result in executing the query more than once.
In your example above, if you changed List<GuitarItems> to IEnumerable<GuitarItems> you're still really returning a List<GuitarItems>, so enumerating that list multiple times does not execute a query repeatedly. But the consumer who now has an IEnumerable<GuitarItems> can't know that, so they'll want to do something like this:
var items = GetGuitarItems("category").ToList();
to make sure that the query is executed once and put into a list that they can enumerate as many times as they want to.
Returning IReadOnlyList<GuitarItems> lets them know that what they have is definitely a list, not something that's going to get queried each time it's enumerated.
This becomes apparent if you use Resharper. If you have an IEnumerable<T> and you enumerate it more than once it will warn you. The item might really be a list or array but you can't know that.
What you want to achieve?
List<T> it is already an IEnumerable<T> because it implements IEnumerable<T> interface so you can treat your List<T> like IEnumerable<T> for example in methods arguments.

Cast IEnumerable<object> to List<object>

I have the following code:
public IList<MyObject> GetSomeData(string inputParam)
{
var temp = repository.GetData(inputParam);
var list = temp as List<MyObject>;
return list;
}
The return value of repository.GetData is IEnumerable<IMyObject>
When I look at the value of temp, it has 400+ records. The moment I cast it to list, it becomes null. Why is this cast not possible?
It returns null because that IEnumerable isn't actually a list. The cast will only succeed if that particularly IEnumerable happens to be a List, instead of some other type of sequence. If you want to have a list, you will need to create a new list and add the items from the sequence into that list.
Unless the underlying object of the value returned from repository.GetData matches what you are trying to cast it to then the result will always be null. Because the generic element types of the method and what is actually return from repository.GetData are different you will need to do some conversions to get the desired result
Assuming that MyObject implements IMyObject I can think of at least to ways using System.Linq to get the result you seek.
Option 1: Cast<T>()
Casts the elements of an System.Collections.IEnumerable to the specified type.
First convert the content of temp using the Cast<MyObject>() linq extension and then use the ToList<T>() extension method to get you resulting IList<MyObject>
public IList<MyObject> GetSomeData(string inputParam)
{
//repository.GetData returns IEnumerable<IMyObject>
var temp = repository.GetData(inputParam);
var list = temp.Cast<MyObject>().ToList();
return list;
}
Option 2: OfType<T>()
Filters the elements of an System.Collections.IEnumerable based on a specified type.
Filter the content of temp using the OfType<MyObject>() linq extension and then use the ToList<MyObject>() extension method to get you resulting IList<MyObject>
public IList<MyObject> GetSomeData(string inputParam)
{
//repository.GetData returns IEnumerable<IMyObject>
var temp = repository.GetData(inputParam);
var list = temp.OfType<MyObject>().ToList();
return list;
}

Recursively execute funcs in list

Given a list of Func<string, string>, is it possible to write a statement that iterates through the list and returns the result like so:
string result = f1(f2(f..(input));
I have the following code (that works), but I'm not satisfied with the temporary variable.
public static string WrapEachElementWith<T>
( this IEnumerable<T> target,
params Func<string, string>[] func )
{
string result = string.Empty;
target.Each(s =>
{
var tmp = s.ToString();
func.Reverse().Each(x => tmp = x(tmp));
result += tmp;
});
return result;
}
How to simplify / refactor?
UPDATE:
I should have provided more background. I'm playing around with Functional programming in c# after seeing higher order JavaScript session and John's abusive c# session at Oredev.
The aim is to generate html.
var TABLE = WrapWith("TABLE");
var TR = WrapWith("TR");
var TD = WrapWith("TD");
const string expected = "<TABLE><TR><TD>1</TD></TR><TR><TD>2</TD></TR></TABLE>";
var result = TABLE(stringArray.WrapEachWith(TR, TD));
result.ShouldEqual(expected);
static Func<String, String> WrapWith(string element)
{
var startTag = '<' + element + '>';
var endTag = "</" + element + '>';
return s => startTag + s + endTag;
}
It looks to me like you're doing four things:
Converting each item to a string
Applying the functions in turn
Applying that composite function to each string in a sequence
Joining the results together (inefficiently)
I would separate out those four aspects - in particular, string.Join works well enough for the fourth part, and Enumerable.Select does the third one.
I would also avoid reversing the order of the operations - I would expect the first operation I specify to be the first one applied, personally.
So, I would rewrite this method to return a Func<string, string> which could then be used with Select and Join. For example:
public static Func<string, string> Compose(params Func<string, string> funcs)
{
return input => {
string current = input;
foreach (var func in funcs)
{
current = func(current);
}
return current;
};
}
You could, of course, make this generic itself, with a signature of:
public static Func<T, T> Compose(params Func<T, T> funcs)
You would then call it with something like:
var composite = Compose<string>(FirstFunction, SecondFunction, ThirdFunction);
var query = string.Join("", items.Select(x => x.ToString())
.Select(composite));
public static string WrapEachElementWith
( string input,
params Func<string, string>[] func )
{
foreach (var f in func.Reverse())
input = f(input);
return input;
}
Not sure why you need template parameter, all the functions map string to string, right?
Note that there's no Each extension of IEnumerable, so you'll have to resort to foreach or write your own Each.
Edit:
your code actually applies this function to all the values from the list, so the actual code would be something like:
public static string F<T>
( this IEnumerable<T> target,
params Func<string, string>[] func )
{
target.Select(item => WrapEachElementWith(item.ToString(), func))
.Aggregate((sum, cur) => sum + cur);
}
As #Jon already mentioned, summing up this way is pretty inefficient, therefore you perhaps would like to put it this way:
string.Join("", target.Select(
item => WrapEachElementWith(item.ToString(), func)));
This guy wrote an entire ray tracer using LINQ. I haven't looked at his code that closely, but he describes using a technique called a "Y-combinator" to create recursion in a LINQ statement. He references this blog posting, which gives a detailed description of these recursive lambda expressions.
I don't know if that's quite what you're looking for, but it might get you off on the right footing.

Simple linq question: using linq to get an array of properties

Lets say we have a simple class
public class Foo
{
public string FooName;
}
Now we want to do some simple work on it.
public void SomeCallerMethod(List<Foo> listOfFoos)
{
string[] fooNames = listOfFoo. // What to do here?
}
If I even knew what method to call, I could probably find the rest of the peices.
You want to transform a list of your class into an array of strings. The ideal method for this is Select, which operates on each element on the enumerable and builds a new enumerable based on the type you return.
You need to put a lambda expression into the select method that returns the name, which will simply be "for each element, select the name".
You then need to cast the output as an array.
string[] fooNames = listOfFoos.Select(foo => foo.FooName).ToArray();
Or, using the other syntax:
string[] fooNames = (from foo in listOfFoos
select foo.FooName).ToArray();

Categories