I am implementing a generic priority queue in C# i used SortedDictionary for the priority keys and Queue for the values.
Now i want to iterate through it with a foreach loop with a condition to skip over queue items with priority 0.
This is my priority queue class
public class PQ<Tpriority, Titem>
{
readonly SortedDictionary<Tpriority, Queue<Titem>> value;
public PQ(IComparer<Tpriority> priorityComparer)
{
value = new SortedDictionary<Tpriority, Queue<Titem>>(priorityComparer);
}
public PQ() : this(Comparer<Tpriority>.Default) { }
public bool Check{ get { return value.Any(); }}
public int Count
{
get { return value.Sum(q => q.Value.Count); }
}
public void Add(Tpriority priority, Titem item)
{
if (!value.ContainsKey(priority))
{
AddQueueOfPriority(priority);
}
value[priority].Enqueue(item);
}
private void AddQueueOfPriority(Tpriority priority)
{
value.Add(priority, new Queue<Titem>());
}
public Titem Next()
{
if (value.Any())
return Next_FHP();
else
throw new InvalidOperationException("The queue is empty");
}
private Titem Next_FHP()
{
KeyValuePair<Tpriority, Queue<Titem>> first = value.First();
Titem nextItem = first.Value.Dequeue();
if (!first.Value.Any())
{
value.Remove(first.Key);
}
return nextItem;
}
public SortedDictionary<Tpriority, Queue<Titem>>.Enumerator GetEnumerator()
{
return value.GetEnumerator();
}
}
public interface IEnumerator<Tpriority, Titem>{}
And this is my main program
I was able to get all my needed actions to work fine just this
static
void Main(string[] args)
{
var first = new PQ<int, string>();
first.Add(1, "random1");
first.Add(0, "random2");
first.Add(2, "random3");
while (first.Check)
{
Console.WriteLine(first.Next());
}
Console.WriteLine(first.Check);
/*it gives the error "Can not convert
type 'System.Collections.Generic.KeyValuePair<int,System.Collections.Generic.Queue<string>>'
to exam.PQ<int, string>"*/
foreach (PQ<int, string> h in first)
{
}
}
Thank you.
One way to do it would be to add your own method on your PQ class, that returns a collection of Queue items that pass your (any) validation check.
So something like this on your PQ class
public IEnumerable<Queue<Titem>> GetItems(Tpriority priority)
{
var validKeys = value.Keys.Where(x => !x.Equals(priority) );
return value.Where(x => validKeys.Contains(x.Key)).Select(x => x.Value);
}
Then you can iterate over it like this
foreach (var h in first.GetItems(0))
{
}
You might want a better name for the method though, which clearly states what it's going to do.
Update...
To just print out the values, you could do something like this.
public IEnumerable<Titem> GetItems(Tpriority priority)
{
var validKeys = value.Keys.Where(x => !x.Equals(priority) );
return value
.Where(x => validKeys.Contains(x.Key))
.SelectMany(x => x.Value);
}
And here it is broken up into bits with a few comments
public IEnumerable<Titem> GetItems(Tpriority priority)
{
// Find all the keys in the dictionary which do not match the supplied value
var validKeys = value.Keys.Where(x => !x.Equals(priority) );
// Find all the values in the dictionary where the key is in the valid keys list
var validItems = value
.Where(x => validKeys.Contains(x.Key));
// Because an individual queue item is actually a collection of items,
// SelectMany flattens them all into one collection
var result = validItems.SelectMany(x => x.Value);
return result;
}
Related
I've a container of data called Meeting
public struct Meeting
{
public string Id { get; set; }
public DateTime Start { get; set; }
public DateTime End { get; set; }
}
This is very simple. It has an Id, and two date times marking the time when this meeting starts and the date time when this meeting end.
I need to return a Lookup that for each day maps all the meeting scheduled for that day.
I've implemented this IEnumerable extension:
public static IEnumerable<ILookup<D, T>> GroupBy<T, D> (this IEnumerable<T> outer,
Func<T, IEnumerable<D>> func)
{
if (outer == null)
throw new ArgumentNullException(nameof(outer));
if (func == null)
throw new ArgumentNullException(nameof(func));
Dictionary<D, IEnumerable<T>> lookup = new Dictionary<D, IEnumerable<T>>();
foreach(T item in outer)
{
IEnumerable<D> keySelectory = func(item);
if (keySelectory != null)
{
foreach(D newKey in keySelectory)
{
if (!lookup.ContainsKey(newKey))
{
lookup.Add(newKey, new List<T>() { item });
}
else
{
List<T> temp = lookup[newKey].ToList();
temp.Add(item);
lookup[newKey] = temp;
}
}
}
}
return WHAT?
}
I'm lost at the end because the Lookup constructor is kept private so I cannot instantiate it.
Because I would like to call something like that:
meetings.GroupBy(meeting => GetDatesFromStartAndEndTimes(meeting));
where the method GetDatesFromStartAndEndTimes is trivial.
Can anyone tell me how to proceed? Thanks.
If you're just wondering how to create a Lookup, you use the LINQ ToLookup extension method:
var meetingsByDate = meetings
.SelectMany(meeting => GetDatesFromStartAndEndTimes(meeting),
(meeting, date) => new{meeting, date})
.ToLookup(pair => pair.date, pair.meeting);
So when you get back an list, one value is filled by the repository but the other you want to have the same value for each item in the list. It feels like an for each loop is the a lot of code for simple functionality. Is there a way to shorten the code.
So some context. This is an example class.
public class ExampleClass
{
public string A { get; set; }
public string B { get; set;
}
This is an method that works:
public IEnumerable<ExampleClass> GetAll(string bValue)
{
var exampleList = repo.GetAll(); //Asume that the repo gives back the an list with A filled;
var returnValue = new List<ExampleClass>();
foreach (var item in exampleList)
{
item.B= bValue;
returnValue.Add(item);
}
return returnValue;
}
It would be great if there could something like:
public IEnumerable<ExampleClass> GetAll(string bValue)
{
return repo.GetAll().Map(i => i.B = bValue);
}
Does anyone knows something like this.
You could use yield return:
public IEnumerable<ExampleClass> GetAll(string bValue)
{
foreach (var item in repo.GetAll())
{
item.B = bValue;
yield return item;
}
}
You can also turn this into an extension method for more fluency:
public static class IEnumerableExtensions
{
public static IEnumerable<T> Map<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var item in source)
{
action(item);
yield return item;
}
}
}
// usage
public IEnumerable<ExampleClass> GetAll(string bValue)
{
return repo.GetAll().Map(x => x.B = bValue);
}
You can try LINQ. According to this link:
Update all objects in a collection using LINQ , you can do this:
repo.getAll().Select(c => {c.B = value; return c;}).ToList();
However, according to Jon Skeet, it's better to just use Foreach loop.
https://stackoverflow.com/a/7851940/5779825
return repo.GetAll().ToList().ForEach(i => i.B = bValue);
This should work. Not tested though.
I think you can use this approach:
return exampleList.Select(i => { i.B = bValue; return i; });
class Animal
{
public FoodTypes Food { get;set;}
public string Name { get; set; }
}
enum FoodTypes
{
Herbivorous,
Carnivorous
}
class Util
{
public static Dictionary<FoodTypes,List<Animal>> GetAnimalListBasedOnFoodType(List<Animal> animals)
{
Dictionary<FoodTypes, List<Animal>> map = new Dictionary<FoodTypes, List<Animal>>();
var foodTypes = animals.Select(o => o.Food).Distinct();
foreach(var foodType in foodTypes)
{
if (!map.ContainsKey(foodType))
map.Add(foodType, null);
map[foodType] = animals.Where(o => o.Food == foodType).ToList();
}
return map;
}
}
The above code is to get the idea of what I am trying to achieve. Now, the question is
Is it possible to achieve the functionality of GetAnimalListBasedOnFoodType in a single lambda expression?
Here you go :)
public static Dictionary<FoodTypes, List<Animal>> GetAnimalListBasedOnFoodType(List<Animal> animals)
{
return animals
.GroupBy(animal => animal.Food)
.ToDictionary(
group => group.Key,
group => group.ToList());
}
You want to use the GroupBy method passing in the property that you want to group the animals by. Then, you can use the ToDictionary method to create your dictionary based on the grouping.
For example:
public static Dictionary<FoodTypes, List<Animal>> GetAnimalListBasedOnFoodType(List<Animal> animals)
{
var animalFoodMap = animals.GroupBy(animal => animal.Food)
.ToDictionary(animalGroup => animalGroup.Key, x => animalGroup.ToList());
return animalFoodMap;
}
I do like this now (thanks to StackOverflow):
IEnumerable<object> Get()
{
var groups = _myDatas.GroupBy(
data => new { Type = data.GetType(), Id = data.ClassId, Value = data.Value },
(key, rows) => new
{
ClassId = key.Id,
TypeOfObject = key.Type,
Value = key.Value,
Count = rows.Count()
}));
foreach (var item in groups)
{
yield return item;
}
}
IEnumerable<MyData> _myDatas;
But is possible to make faster or more "elegant" by not having last foreach loop, but yielding it when the group/anonymous class instance is created?
I would guess fastest way would be to write it open and:
sort the _myDatas
enumerate it and when group changes yield the last group
But I'm trying to learn some LINQ (and C# features in general) so I don't want to do that.
The rest of example is here:
public abstract class MyData
{
public int ClassId;
public string Value;
//...
}
public class MyAction : MyData
{
//...
}
public class MyObservation : MyData
{
//...
}
You should be able to return groups directly, though you might need to change your return type from IEnumerable<Object> to just IEnumerable.
So:
IEnumerable Get()
{
var groups = _myDatas.GroupBy(
// Key selector
data => new {
Type = data.GetType(),
Id = data.ClassId,
Value = data.Value
},
// Element projector
(key, rows) => new
{
ClassId = key.Id,
TypeOfObject = key.Type,
Value = key.Value,
Count = rows.Count()
}
);
return groups;
}
groups has the type IEnumerable< IGrouping< TKey = Anonymous1, TElement = Anonymous2 > >, so you can return it directly.
I have two simple classes. One is called UseCounter<T> and is a simple container for other objects while holding some information about its use (how many times it's been already used and if it can be reused once again).
Then there is Dispenser<T>, which holds a collection of UseConter<T> and is used to get the right element from the collection and then update its information.
The trouble I have is in the Dispenser's Get() method. It should return the object with the lowest combination of Count and TotalCount, and then call Increase() method in order to increase count.
However, when I run this code, Dispenser<T> always returns the same element. It's like the Linq'd element wasn't a reference to the object, but its copy, so the Increase() method increases only the local object's properties, but not the one in the collection.
I am at loss here, because I have never encountered such a behaviour.
Here comes the code:
UseCounter:
public class UseCounter<T>
{
public T Element { get; private set; }
public int TotalCount { get; private set; }
public int Count { get; private set; }
public bool Useful { get; set; }
public UseCounter(T element)
{
this.Element = element;
this.Count = 0;
this.TotalCount = 0;
this.Useful = true;
}
public void IncreaseCounter()
{
this.Count++;
this.TotalCount++;
}
public void DecreaseCounter()
{
if(this.Count == 0)
{
throw new ArgumentOutOfRangeException("Count cannot be lower than 0!");
}
this.Count--;
}
}
Dispenser:
private readonly object _elementLocker = new object();
private IEnumerable<UseCounter<T>> _elements;
public IEnumerable<T> Elements
{
get { return _elements.Select(e => e.Element); }
}
public int FinishedCount
{
get
{
lock (_elementLocker)
{
return _elements.Where(e => e.Useful == false).Count();
}
}
}
public int CurrentlyWorkingCount
{
get
{
lock (_elementLocker)
{
return _elements.Where(e => e.Count > 0).Count();
}
}
}
public Dispenser(IEnumerable<T> elements)
{
this._elements = elements
.Distinct()
.Select(e => new UseCounter<T>(e));
}
public T Get()
{
lock(_elementLocker)
{
var lCount = _elements
.Where(e => e.Useful == true)
.Select(e => e.Count).Min();
var lTCount = _elements
.Where(e => e.Useful == true)
.Where(e => e.Count == lCount)
.Select(e => e.TotalCount).Min();
var el = _elements
.Where(e => e.Useful == true)
.First(e => e.Count == lCount && e.TotalCount == lTCount);
el.IncreaseCounter();
return el.Element;
}
}
public void Report(T element, bool successful)
{
lock(_elementLocker)
{
var el = _elements
.First(e => e.Element == element);
el.DecreaseCounter();
if(el.Useful == true && successful == true)
{
el.Useful = false;
}
}
}
This is the problem:
this._elements = elements
.Distinct()
.Select(e => new UseCounter<T>(e));
This is lazy. Every time you iterate over _elements, it will go back to the original source data, find a distinct set, and then project that set onto a new sequence of UseCounter instances. Any changes you make to those instances are irrelevant to what happens when you next iterate over _elements.
If you're happy for the set of input elements to be "frozen" on construction, you can just materialize the query so it only executes once:
this._elements = elements
.Distinct()
.Select(e => new UseCounter<T>(e))
.ToList();
Now every time you iterate over elements, you're iterating over the same sequence of references.