Is there a way to Translate an array into a dictionary - c#

The problem I'm having is that I'm not sure how to translate my double array into a Dictionary. I have some LINQ Where statements that are pretty heavy, so I wanted to use the keys of my Dictionary to look up a specific value. I have two classes with getters and setters and then my calculator.
I've fiddled around a bit with trying to make either a lookup or a Dictionary, but didn't have any luck.
public class Product
{
public int EarliestOriginYear { get; set; }
public int NoOfDevelopmentYears { get; set; }
public string ProductName { get; set; }
public IEnumerable<ProductIncrementalValue> ProductIncrementalValues { get; set; }
}
public class ProductIncrementalValue
{
public string ProductName { get; set; }
public int OriginYear { get; set; }
public int DevelopmentYear { get; set; }
public double IncrementalValue { get; set; }
}
public IList<double> Calculate(Product product)
{
IList<double> cumulativeDataTriangle = new List<double>();
if (!product.ProductIncrementalValues.Any())
return cumulativeDataTriangle;
for (int i = 0; i < product.NoOfDevelopmentYears; i++)
{
// This is what I want to change (where statements)
var incrementalValues = product.ProductIncrementalValues
.Where(v => v.OriginYear == product.EarliestOriginYear + i)
.ToList();
double previous = 0;
for (int j = 0; j < product.NoOfDevelopmentYears - i; j++)
{
// This is what I want to change
double incrementalValue = incrementalValues.Where(val =>
val.DevelopmentYear == val.OriginYear + j)
.Select(x => x.IncrementalValue)
.FirstOrDefault();
var tmp = incrementalValue + previous;
cumulativeDataTriangle.Add(tmp);
previous = tmp;
}
}
return cumulativeDataTriangle;
}

You could group the products by OriginYear and DevelopmentYear before the loops. Something like this might help:
public IList<double> Calculate(Product product)
{
IList<double> cumulativeDataTriangle = new List<double>();
if (!product.ProductIncrementalValues.Any())
return cumulativeDataTriangle;
var lookup = product.ProductIncrementalValues.ToLookup(v => (v.OriginYear, v.DevelopmentYear), v => v.IncrementalValue);
for (int i = 0; i < product.NoOfDevelopmentYears; i++)
{
var originYear = product.EarliestOriginYear + i;
double previous = 0;
for (int j = 0; j < product.NoOfDevelopmentYears - i; j++)
{
var developmentYear = originYear + j;
var incrementalValues = lookup[(originYear, developmentYear)];
double incrementalValue = incrementalValues.FirstOrDefault();
var tmp = incrementalValue + previous;
cumulativeDataTriangle.Add(tmp);
previous = tmp;
}
}
return cumulativeDataTriangle;
}

Thanks to the previous answer, I managed to implement a Dictionary based on OriginYear and DevelopmentYear, which returns an IncrementalValue.
public IList<double> Calculate(Product product)
{
IList<double> cumulativeDataTriangle = new List<double>();
if (!product.ProductIncrementalValues.Any())
return cumulativeDataTriangle;
var lookup = product.ProductIncrementalValues.
ToDictionary(v => (v.OriginYear, v.DevelopmentYear), v => v.IncrementalValue);
for (int i = 0; i < product.NoOfDevelopmentYears; i++)
{
var originYear = product.EarliestOriginYear + i;
double previous = 0;
for (int j = 0; j < product.NoOfDevelopmentYears - i; j++)
{
var developmentYear = originYear + j;
double incrementalValue;
lookup.TryGetValue((originYear, developmentYear), out incrementalValue);
var tmp = incrementalValue + previous;
cumulativeDataTriangle.Add(tmp);
previous = tmp;
}
}
return cumulativeDataTriangle;
}

Related

Using multiple channels, what am I doing wrong?

I want to create an array of Tasks, called listTask, with each element of listTask is a Task of type A, Task of type A is created by the function Task.WhenAll. then I do await Task.WhenAll(listTask) But the program does not perform the work in the listTask array. I set debug and those tasks were completed, I don't understand why
namespace Ding.LearningNewThings
{
public class MultiChannelTask
{
public static async Task RunMiltipleChannel()
{
ConcurrentDictionary<int, Channel<Position>> _dataChannels = new ConcurrentDictionary<int, Channel<Position>>();
var listPlace = Place.InitData();
var numberOfPlace = listPlace.Count();
for (int i = 0; i < listPlace.Count(); i++)
{
_dataChannels.TryAdd(i, Channel.CreateUnbounded<Position>());
}
Task[] listStationTask = new Task[numberOfPlace];
for (var j = 0; j < numberOfPlace; j++)
{
var listTask = new Task[2];
var placeOuter = listPlace[j];
listTask[0] = Task.Run(async () =>
{
int IndexOfPlace = j;
var place = new Place()
{
ID = placeOuter.ID,
Name = placeOuter.Name
};
Channel<Position> dataChannel;
var r = new Random();
if (_dataChannels.TryGetValue(IndexOfPlace, out dataChannel))
{
var position = new Position()
{
PlaceID = place.ID,
PlaceName = place.Name,
ID = r.Next(1, 100)
};
await dataChannel.Writer.WriteAsync(position);
Console.WriteLine($"Push postion ID {position.ID}, Place ID {position.PlaceID}");
}
});
listTask[1] = Task.Run(async () =>
{
var IndexOfPlace = j;
Channel<Position> dataChannel;
var r = new Random();
if (_dataChannels.TryGetValue(IndexOfPlace, out dataChannel)) {
var position = await dataChannel.Reader.ReadAsync();
Console.WriteLine($"Get postion ID {position.ID}, Place ID {position.PlaceID}");
}
});
listStationTask[j] = Task.WhenAll(listTask);
}
await Task.WhenAll(listStationTask);
}
}
public class Place
{
public int ID { get; set; }
public string Name { get; set; }
public static List<Place> InitData()
{
var listData = new List<Place>();
for (int i = 0; i < 10; i++)
{
var data = new Place()
{
ID = i,
Name = $"Postion{i}",
};
listData.Add(data);
}
return listData;
}
}
public class Position
{
public int ID { get; set; }
public int PlaceID { get; set; }
public string PlaceName { get; set; }
public string Name { get; set; }
public static List<Position> InitData()
{
var listData = new List<Position>();
for (int i = 0; i < 10; i++)
{
var data = new Position()
{
ID = i,
Name = $"Postion{i}"
};
listData.Add(data);
}
return listData;
}
}
}
I seem the task have had done ahead of intended. Sometimes it works, but I don't know why the job always completes without running in the list task code.

C# Unify Duplicated Methods different parameter types

I Had to duplicate this method (made by another person) but I wanna know if there is a way to unify it,
this one receives an IList<ViewModelA>,
I need to pass to it an IList<ViewModelB>
with different properties, but the ones used in the method are in both are the same like fatherId or Items
I wanna know if there is a way to unify those methods with inheritance or interface or something else.
private IList<ViewModelA> TrasnformToTree(IEnumerable<ViewModelA> source)
{
var modelGroups = source.GroupBy(i => i.fatherId);
var roots = modelGroups.FirstOrDefault(g => g.Key.HasValue == false).ToList();
if (roots.Count > 0)
{
var dict = modelGroups.Where(g => g.Key.HasValue)
.ToDictionary(g => g.Key.Value, g => g.ToList());
for (int i = 0; i < roots.Count; i++)
{
if (dict.ContainsKey(roots[i].Id))
{
roots[i].Items = dict[roots[i].Id];
for (int j = 0; j < roots[i].Items.Count; j++)
AddChildren(roots[j].Items[j], dict);
}
else
{
roots[i].Items = new List<ViewModelA>();
}
}
}
return roots;
}
this should work for the code i'm seeing:
private interface ISomeInterface<T>
{
int Id { get; set; }
int? fatherId { get; set; }
List<T> Items { get; set; }
}
private IList<T> TrasnformToTree<T>(IEnumerable<T> source) where T : ISomeInterface<T>
{
var modelGroups = source.GroupBy(i => i.fatherId);
var roots = modelGroups.FirstOrDefault(g => g.Key.HasValue == false).ToList();
if (roots.Count > 0)
{
var dict = modelGroups.Where(g => g.Key.HasValue)
.ToDictionary(g => g.Key.Value, g => g.ToList());
for (int i = 0; i < roots.Count; i++)
{
if (dict.ContainsKey(roots[i].Id))
{
roots[i].Items = dict[roots[i].Id];
for (int j = 0; j < roots[i].Items.Count; j++)
AddChildren(roots[j].Items[j], dict);
}
else
{
roots[i].Items = new List<T>();
}
}
}
return roots;
}

Iterate through ObservableCollection of class

I'm assigning values to a class by using ObservableCollection.Class contains MainItems and it's SubItems. Now how can I read all SubItems for each input of MainItem?
public class MainItems
{
public string ItemName { get; set; }
public ObservableCollection<SubItems> SubItemsList { get; set; }
}
public class SubItems
{
public string SubItemName { get; set; }
}
ObservableCollection<MainItems> _data = new ObservableCollection<MainItems>();
for (int i = 1; i <= 5; i++)
{
MainItems _mainItems = new MainItems();
_mainItems.ItemName = "Main" + i.ToString();
_mainItems.SubItemsList = new ObservableCollection<SubItems>();
for (int j = 1; j <= 3; j++)
{
SubItems _subItems = new SubItems()
{
SubItemName = "SubItem" + i.ToString()
};
_mainItems.SubItemsList.Add(_subItems);
}
_data.Add(_mainItems);
}
The foreach loop alway honors the collections(List, Array, Dictionary(special), ...) boundaries and iterates over all Elements, so its the shortest way to achieve what you want. It disallows you to add/remove elements from the currently iterated collection. In this case the classic for loop is your friend.
Full description from Microsoft:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in
Based on Fangs comment:
// foreach Version
foreach (MainItems mainItem in _data)
{
foreach (SubItems subItems in mainItem.SubItemsList)
{
Console.WriteLine($"{mainItem.ItemName} has a child {subItems.SubItemName}!");
}
}
// for Version
for (int i = 0; i < _data.Count; i++)
{
MainItems mainItem = _data[i];
for (int k = 0; k < mainItem.SubItemsList.Count; k++)
{
SubItems subItem = mainItem.SubItemsList[k];
Console.WriteLine($"{mainItem.ItemName} has a child {subItem.SubItemName}!");
}
}
// For Enumerator version
// get the input main item
string input = "Main1";
IEnumerable<ObservableCollection<SubItems>> ItemsforSelectedMainIem = _data.Where(x => x.ItemName == input).Select(x => x.SubItemsList);
var e = ItemsforSelectedMainIem.GetEnumerator();
while (e.MoveNext())
{
var v = e.Current.Select(x=>x.SubItemName).ToList();
foreach (var item in v)
{
Console.WriteLine(item);
}
}

How to change an object that was mocked?

In my Unit Test I need to change the value of the object that was mocked before. For example:
public class Cell
{
public int X { get; set; }
public int Y { get; set; }
public string Value { get; set; }
}
public class Table
{
private Cell[,] Cells { get; }
public Table(Cell[,] cells)
{
Cells = cells;
}
public void SetCell(int x, int y, string value)
{
Cells[x, y].Value = value;
}
}
I want to test SetCell method in Table.
So, first I mock Cell, then I create a Cell[,] array of cells, create a Table passing array of cells as a parameter.
SetCell doesn't work, because (I think) I can't change the object that was mocked before. How can I change it?
Here's my test:
ICell[,] cells = new ICell[3, 4];
for (int i = 0; i < cells.GetLength(0); i++)
{
for (int j = 0; j < cells.GetLength(1); j++)
{
var mock = new Mock<ICell>();
mock.Setup(m => m.X).Returns(i);
mock.Setup(m => m.Y).Returns(j);
mock.Setup(m => m.Value).Returns("");
cells[i, j] = mock.Object;
}
}
ITable table = new Table(cells);
table.SetCell(0, 0, "TEST"); // Cannot change it here :/
Setup all the properties so that they can be updated
ICell[,] cells = new ICell[3, 4];
for (int i = 0; i < cells.GetLength(0); i++)
{
for (int j = 0; j < cells.GetLength(1); j++)
{
var mock = new Mock<ICell>();
mock.SetupAllProperties();
mock.Object.X = i;
mock.Object.Y = j;
mock.Object.Value = "";
cells[i, j] = mock.Object;
}
}
//...other code removed for brevity

Remove item in the third level of a dictionary

I am trying to remove information that is in the third level of a dictionary and can only use it after the removal of this information.
But I can not, what am I doing wrong?
public class Person
{
int id;
string name;
public string Name
{
get { return name; }
set { name = value; }
}
public int ID
{
get { return id; }
set { id = value; }
}
public List<Product> ListProd;
}
public class Product
{
public int idProd;
public string Description;
public List<Tax> listTax;
}
public class Tax
{
public int idTax;
public string Value;
}
//Method
public void SomeMethod()
{
Dictionary<int, List<int>> dicRemove = new Dictionary<int, List<int>>();
List<int> listTaxToRemove = new List<int>();
for (int m = 8; m < 10; m++)
{
listTaxToRemove.Add(m);
}
dicRemove.Add(10, listTaxToRemove);
Dictionary<int, List<Person>> dic = new Dictionary<int, List<Person>>();
List<Person> list = new List<Person>();
for (int i = 0; i < 2; i++)
{
Person d = new Person();
d.ID = i;
d.Name = "Person " + i;
d.ListProd = new List<Product>();
for (int j = 3; j < 6; j++)
{
Product p = new Product();
p.idProd = j;
p.Description = "Product " + j;
d.ListProd.Add(p);
p.listTax = new List<Tax>();
for (int m = 7; m < 10; m++)
{
Tax t = new Tax();
t.idTax = m;
t.Value = "Tax " + m;
p.listTax.Add(t);
}
}
list.Add(d);
}
dic.Add(10, list);
var q = dic.Select(s => s.Value
.Select(s1 => s1.ListProd
.Select(s2 => s2.listTax
.RemoveAll(r =>!dicRemove[s.Key].Contains(r.idTax))))).ToList();
}
I tried a number of ways, through iterations, this approach had just deleting unnecessary records.
Thank you!
RemoveAll is not invoked due to deferred execution of Select
you have 3 Select and only one ToList()
q has type System.Collections.Generic.List'1[System.Collections.Generic.IEnumerable'1[System.Collections.Generic.IEnumerable'1[System.Int32]]]
there are nested IEnumerable object which were not enumerated
here is a working variant but absolutely unreadable, don't do it like this
var q = dic.Select(s => s.Value.Select(s1 => s1.ListProd.Select(s2 => s2.listTax.RemoveAll(r=>!dicRemove[s.Key].Contains(r.idTax)))
.ToList())
.ToList())
.ToList();
improved variant
foreach(var pair in dic)
foreach(var person in pair.Value)
foreach(var prod in person.ListProd)
prod.listTax.RemoveAll(t=>!dicRemove[pair.Key].Contains(t.idTax));

Categories

Resources