I have a multithreaded app that is creating a list of strings on a BlockingCollection queue, I want to take that list of strings and convert it to a collection of item objects in one or 2 steps
Is it possible to create a func<> or lamda method to achieve this type of result
public class item
{
public string name { get; set; }
public item(string nam)
{
name = nam;
}
}
IList<string> alist = new string[] { "bob","mary"};
Where you take a Ilist<> or IEnumerable<> of type string and return IList
So for the single item Func<>
Func<string, item> func1 = x => new item(x);
But essetially the signiture would look like
Func<IEnumerable<string>,IList<item>> func2 = x=> x.ForEach(i => func1(i));
Am I trying to put a round peg in sqaure hole or is my syntax/logic just wrong
Thanks in advance
Are you just trying to "reshape" the IList<string> as IList<item>?
IList<string> listOfStrings = new string[] { "bob","mary"};
IList<item> listOfItems = listOfStrings.Select(s => new item(s)).ToList();
You will have to use a Select projection instead of ForEach and then convert the resulting IEnumerable<item> to a list using ToList() - this should work:
Func<IEnumerable<string>,IList<item>> func2 = x => x.Select( i => new item(i)).ToList();
IEnumerable<item> myfunc(IEnumerable<string> stringlist)
{
var q = from s in stringlist
select new item(s);
return q.ToList();
}
Related
I have a list like this:
public class list
{
public IList<list2> list {get;set;}
}
And a list2 like this:
public class list2
{
public string something {get;set;}
}
The result I want is this:
var listWithAll = new List<list2>();
foreach (var item in list)
{
foreach (var item2 in item.list)
{
listWithAll.Add(item2);
}
}
Is there a short LINQ handler I can use do to this?
Something like this:
list.Select(x => x.list);
But this doesn't work obviously.
Use SelectMany method of LINQ
var newlist = list.SelectMany(x => x.list).ToList();
SelectMany flattens queries that return lists of lists.
For further details refer here
You can use SelectMany for this purpose:
var listWithAll = list.SelectMany(x => x.list).ToList();
The SelectMany:
Projects each element of a sequence to an IEnumerable<T> and flattens the resulting sequences into one sequence.
I have a class that extends List:
public class MyObjectList : List<MyObject>
{
...
}
Currently, there is a LINQ statement that groups by a key value:
MyObjectList objects = new MyObjectList(); //initializes and loads list
var objectsByKey = objects.GroupBy(obj => obj.MyKey)
.Select(objs => new {MyKey = objs.Key, MyObjs = objs.ToList()})
.ToList();
In the output, MyObjs is of type List< MyObject>, and it lists the correctly grouped objects.
When I try to cast it as MyObjectList, MyObjs ends up being null.
var objectsByKey = objects.GroupBy(obj => obj.MyKey)
.Select(objs => new {MyKey = objs.Key, MyObjs = objs.ToList() as MyObjectList})
.ToList();
How can I get MyObjs to be of type MyObjectList, with the correclty grouped objects?
In your MyObjectList class, provide a constructor like so:
public class MyObjectList : List<MyObject>
{
public MyObjectList(IEnumerable<MyObject> list)
:base(list)
{
}
}
Then, when selecting out your objects, do it like this:
var objectsByKey = objects.GroupBy(obj => obj.MyKey)
.Select(objs => new {MyKey = objs.Key, MyObjs = new MyObjectList(objs)})
.ToList();
Enumerable.ToList (the extension method that you are using) does not know about your custom list type. Casting will not convert it.
You need to instantiate and fill the list yourself. There are at least two ways of doing it:
Constructor
public MyObjectList(IEnumerable<MyObject> collection) : base(collection) {}
You'd have to replace the objs.ToList() call with new MyObjectList(objs)
Extension method
public static class MyObjectListExtensions
{
public static MyObjectList ToList(this IEnumerable<MyObject> collection)
{
//You could also call the constructor described above
var list = new MyObjectList();
list.AddRange(collection);
return list;
}
}
With this, you don't have to change your code, as long as you include the namespace of MyObjectListExtensions in your file. Why? Because being non-generic, MyObjectListExtensions.ToList takes precedence over Enumerable.ToList.
If you don't want MyObjectList to be instantiated always, you could use a different name.
I know this can be solved using a for-loop and a model class but I am curious how would you do this using only lambda expressions with a resulting anonymous object.
Say I have a class
public class GameReport
{
public GameReport()
{
Entries = new List<ReportEntry>();
}
public string GameName { get; set; }
public List<ReportEntry> Entries { get; set; }
}
and using this class I instantiated an object
List<GameReport> gameReports = new List<GameReport>();
I then populate this list with the necessary values (including the Entries list), now I need to use a Lambda expression to create a new list composed of anonymous objects that contains something like
new { GameName, SingleEntry}
Thanks in advance!
var items = (from g in gameReports
from e in g.Entries
select new { g.GameName, Entry = e }).ToList();
Or using SelectMany method with method-based query:
var items = gameReports.SelectMany(g => g.Entries
.Select(e => new
{
g.GameName,
Entry = e
})).ToList();
The first one will be transformed into the second one by compiler on compilation.
I have a following collection, it has more than 500000 items in it.
List<Item> MyCollection = new List<Item>();
and type:
class Item
{
public string Name { get; set; }
public string Description { get; set; }
}
I want to return a list of items having distinct Name. i.e. to find out distinct item based on name.
What are the possible ways & which would be best in terms of time & memory. Although both are important however less time has more priority over memory.
I would opt for Linq, unless or until the performance turns out to be insufficient:
var considered = from i in MyCollection
group i by i.Name into g
select new { Name = g.Key, Cnt = g.Count(), Instance = g.First() };
var result = from c in considered where c.Cnt == 1 select c.Instance;
(Assuming I've interpreted your question correctly as "return those items whose Name only appears once in the list")
i am having java version of the code
implement the comparator then define the method as below in Item class
public int compare(MyObject o1, MyObject o2)
{
// return 0 if objects are equal in terms of your data members such as name or any
}
Then use the below code in the class in which MyCollection is defined
HashSet<Item> set1 = new HashSet<Item>();
set1.addAll(MyCollection);
MyCollection.clear();
MyCollection.addAll(set1);
This will give you the sorted set
You can sort your list an then delete all repeated items, But seems that storing all data in a Dictionary<string, string> would be better for this task. Or maybe even put all the list in a HashSet.
MoreLinq has a DistinctBy extension that is great for this sort of thing, its open source and just a few lines of code so easy to add to your code.
var results = MyCollection.DistinctBy(p => p.Name);
I can see you found your answer, but you can also do it fairly simply using Distinct;
internal class NameComparer : IEqualityComparer<Item> {
public bool Equals(Item x, Item y) { return x.Name == y.Name; }
public int GetHashCode(Item obj) { return obj.Name.GetHashCode(); }
}
var distinctItems = MyCollection.Distinct(new NameComparer());
First solution:
public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> sequence, Func<T, TKey> keySelector)
{
var alreadyUsed = new HashSet<TKey>();
foreach (var item in sequence)
{
var key = keySelector(item);
if (alreadyUsed.Add(key))
{
yield return item;
}
}
}
Second is to use .Distinct() and override Equals in your item to match name
I have two different lists where one is a bunch of ID's as in a List<int> idsList, the other however is a list of objects like List<MyObject> myObjectList where the object looks like this:
class MyObject{
private List<int> ids;
public MyObject(List<int> ids){
this.ids = ids;
}
public List<int> Ids{
get{
return ids;
}
}
}
As you can see each object can contain one or multiple IDs (never zero or null ids). So what I need at the end is to know what objects in myObjectList have any id(s) from my idsList.
So far if I do:
var ids = from g in onScreen where g.Ids.Contains(myIntVariable) select g;
it would give me a list of the object(s) that contain myIntVariable. What I do not know how to do is to match the content of the idsList with the list in MyObject.
Thanks!
One way to go:
var listOfMyObjectsContainingAnIdFromIdsList = myObjectList.Where(myObject => myObject.Ids.Any(id => idsList.Contains(id)));
Assuming g is your object list and idsList is your int list:
foreach (var myObject in g.Where( obj => obj.Ids.Any( itemId => idsList.Contains(itemId) ) )) {
//Use your myObject here
}
Hope it works,