Reputation: 35
Im sure im not the first person to have this happen but ive tried from several different angles to resolve this and im having the same problem
I am retrieving items from a database, and i only want the last item for each position.
class Item {
public bool is_scheduled {get;set;}
public int round{get;set;}
public int round_position {get;set;}
[NotMapped]
public int position {get;set;}
public int ItemsRequired{get;set;}
}
if the ItemsRequired is greater than 1, then i need to add copies of the same item to the list.
after ive created the copy, I am then trying to renumber the item, which seems to work properly.
When i check the list as a whole, i have duplicates of the numbers though.
using (var context = new DBContext)
{
var items = context.Items
.Where(o => o.round == round && o.is_scheduled == false)
.GroupBy(o => o.round_position)
.ToList()
.Select(GetLastItem)
.ToList();
foreach (var item in items)
{
Trace.WriteLine($"{item.position}");
}
return ParseItems(items);
}
private static List<Item> ParseItems(List<Item> items)
{
var result = new List<Item>();
var idx = 0;
foreach (var item in items)
{
var carries = item.ItemsRequired.GetValueOrDefault();
if (carries == 1)
{
idx = idx + 1;
item.position = idx;
Trace.WriteLine($"pos:{item.position}");
result.Add(item);
}
else
{
for (var i = 0; i < carries; i++)
{
idx = idx + 1;
item.position = idx;
Trace.WriteLine($"pos:{item.position}");
result.Add(item);
}
}
}
foreach (var r in result)
Trace.WriteLine(r.position);
return result;
}
private static Item GetLastItem(IGrouping<int?, Item> arg)
{
var items = arg
.OrderBy(o => o.date_created)
.ToList();
var last = items.Last();
return last;
}
So if i were to take the items and assign a position as such.
items = items.Select((item,idx)=>{
var clone = item;
clone.position=idx;
return clone;}).ToList();
// Print items
foreach(var item in items)
Trace.WriteLine(item.position);
this currently shows duplicates of numbers in the output window.
Upvotes: 0
Views: 189
Reputation: 35
I found the answer on my own, but i could really use help understanding why.
if i take
// Wrong
items.Select((item,i)=>{
item.position=i;
return item;
}).ToList();
foreach(var item in items)
Trace.WriteLine(item.position);
// This seems to work
items.Select((item,i)=>{
var result = new Item{position=i};
return result;
}).ToList();
foreach(var item in items)
Trace.WriteLine(item.position);
Upvotes: 0
Reputation: 1200
The inner for loop you have will be actually updating the same item over and over again as it is a reference type. You will instead need to create a new instance on Item
.
...
else
{
for (var i = 0; i<carries; i++)
{
idx = idx + 1;
var itemClone = new Item();
itemClone.position = idx
itemClone.is_scheduled = item.is_scheduled;
//...set other itemClone property values
Trace.WriteLine($"pos:{itemClone.position}");
result.Add(itemClone);
}
}
...
Upvotes: 1
Reputation: 332
using(var context = new DBContext)
{
var items = context.Items
.Where(o => o.round == round && o.is_scheduled == false)
.GroupBy(o=>o.round_position)
.Select(x => new {Roundposition = x.Key, Item = x.LastOrDefault()})
.ToList();
}
Upvotes: 0
Reputation: 34427
A group create a two dimension array. The long item (key) is the group and the short item is each item in the long array. So you need to use a select to enumerate through the keys and get last item of each key. Try following :
using(var context = new DBContext){
.Where(o => o.round == round && o.is_scheduled == false)
.GroupBy(o=>o.round_position)
.Select(x => x.LastOrDefault())
.ToList();
}
Upvotes: 0