How to change a value in C# ConcurrentQueue - c#

I would like to change/set one of the values in the ConcurrentQueue. FixedSizedQueue is a ConcurrentQueue. I think the main issue I'm having to trying to get the ONE of the entries in this ConcurrentQueue. Any suggestions...
private void CalculateABC(FixedSizedQueue<Bar> q)
{
decimal sum = 0.0m;
foreach (var item in q.Queue)
{
sum = sum + item.close;
}
decimal ABCvalue = decimal.Round(sum / q.Limit, 5);
//I'm trying to set the value HERE.
//((Bar)(q.Queue)Items[19]).ABC = ABCvalue;
}

private void CalculateABC(FixedSizedQueue<Bar> q)
{
decimal sum = 0.0m;
Bar item19 = null;
int index = 0;
foreach (var item in q.Queue)
{
if (index++ == 19)
item19 = item;
sum = sum + item.close;
}
decimal ABCvalue = decimal.Round(sum / q.Limit, 5);
//I'm trying to set the value HERE.
if (item19 != null)
item19.ABC = ABCvalue;
}

It seems to me that you just need to do this:
private void CalculateABC(FixedSizedQueue<Bar> q)
{
q.Queue.Skip(19).First().ABC =
decimal.Round(q.Queue.Sum(x => x.close) / q.Limit, 5);
}
Obviously you must ensure that your queue has at least 20 elements for this to work.

While you may want to reevaluate using a queue instead of a list (or in this case a ConcurrentQueue instead of a ConcurrentBag) because it won't provide random access (and you'll need to enumerate all previous elements to get to the one you want) it still is an IEnumerable so you can use LINQ to index it, but the performance will be poor as indexing the 1000th element doesn't require going to adress of first element + 1000 but going over each of the previous 999 elements.
In any case the simplest solution if you want to stick with a queue and index it is to replace your example of
queue[19]
with
queue.ElementAt(19)
So the full example would be :
private void CalculateABC(FixedSizedQueue<Bar> q)
{
// Replace your summing of each item's close property with a simple LINQ sum
decimal sum = q.Queue.Sum(item=>item.close);
decimal ABCvalue = decimal.Round(sum / q.Limit, 5);
// No need for any casting, you're already working on generics, it's already a Bar, don't cast a Bar to a Bar
q.Queue.ElementAt(19).ABC = ABCvalue;
}

Related

How can I use a Lambda Expression to calculate a function in C# with variables from multiple nodes in a LinkedList<object>?i

static void Main(string[] args)
{
LinkedList<Day> Days = new LinkedList<Day>();
Day day1 = new Day() { sunUp = 800, sunDown = 1800 };
Day day2 = new Day() { sunUp = 755, sunDown = 1805 };
Day day3 = new Day() { sunUp = 750, sunDown = 1810 };
Day day4 = new Day() { sunUp = 745, sunDown = 1815 };
Day day5 = new Day() { sunUp = 740, sunDown = 1820 };
Days.AddLast(day1);
Days.AddLast(day2);
Days.AddLast(day3);
Days.AddLast(day4);
Days.AddLast(day5);
Console.WriteLine("There is an average of {0} minutes of night over the past {1} days.", Calculator(Days), Days.Count);
}
public static int ToMinutes(int time)
{
return time / 100 * 60 + time - time / 100 * 100;
}
class Day
{
public int sunUp;
public int sunDown;
}
public static int Calculator(LinkedList<Day> Days)
{
var current = Days.First;
int nightDuration = 0;
int count = 0;
while (current.Next != null)
{
nightDuration += ToMinutes(current.Value.sunDown) - ToMinutes(current.Next.Value.sunUp);
current = current.Next;
count++;
}
return nightDuration/count;
}
Requirement: Day must be stored in a LinkedList.
Is there a clean Lambda Expression equivalent to the Calculator method above? I am having trouble using Lambda's to calculate a function with variables across connected nodes.
Thanks for the help!
Cheers,
Kyle
Quite a few things are wrong with your pseudo code of using a calculator (for addition in this instance)
You have a class that has two integers. I believe your idea is to add the two numbers together along with two numbers from every other node of the linked list. But, you are adding only the first number from Pair and adding it to 2nd number of the next node... dont think it will work.
array = current.value.int1 + current.Next.value.int2;
should be
array = current.value.int1 + current.value.int2;
Working Example
public static int Calculator(LinkedList<Pair> Pairs)
{
var current = Pairs.First;
int sum = 0;
while (current != null)
{
sum += current.Value.num1 + current.Value.num2;
current = current.Next;
}
return sum;
}
Ran this in the main,
LinkedList<Pair> Pairs = new LinkedList<Pair>();
Pair pair = new Pair() { num1 = 1, num2 = 5 };
Pairs.AddFirst(pair);
Pairs.AddLast(pair);
Pairs.AddLast(pair);
Console.WriteLine( Calculator(Pairs));
Output
18
Lambda expression you can use to add up all the linked lists can be summed up as,
Console.WriteLine(Pairs.Sum(x => x.num1 + x.num2));
Output
18
Hope it helps
Looking at your example i see what you're trying to say. So you want to the same logic as in your Calculator method but using Lambda expression. The most easy way to do this is to use Language Integrated Query (LINQ).
So breaking up your Calculator() method we see it actually contains 2 elements.
Sum up each value after you've combined num1 with num2 in the List
Divide the end result with the total count in the list.
The most easy way to do this is by using Enumerable.Sum and then devide that value by the count of the list. For example:
Pairs.Sum(pair => pair.num1 + pair.num2) / Pairs.Count
Result: 6
Here a code example
Enumerable.Sum is extension method from System.Linq namespace. It returns sum of numeric values in collection.
Although Lambda expressions are awesome, please do bare in mind that readability is also very important. They are basically anonymous functions which, if the logic gets complex, will be hard to understand for other developers/team members.
Hope this helps. Good luck!
EDIT
So if i understand it correctly you're having a hard time using lambda expressions with nested methods. Like for example your Calculator() method makes use of another method ToMinutes.
Using the code from my first example, we can still use the logic. The most important part we have to change is the logic within the Sum. E.g.
Days.Sum(day => ToMinutes(day.sunDown) - ToMinutes(day.sunUp )) / totalDays;
This is just one of the ways to do it. Another option is to create an ExtensionMethod. E.g.
namespace ExtensionMethods
{
public static class IntExtensions
{
public static int ToMinutes(this int time)
{
return time / 100 * 60 + time - time / 100 * 100;
}
}
}
Above the class you want to use the extension method just include it by writing
using ExtensionMethods;
at the top of your document.
This will give another option to all your integers to parse the value to a different value. In our case, to minutes.
int totalDays = Days.Count;
int averageMinutes = Days.Sum(day => day.sunDown.ToMinutes() - day.sunUp.ToMinutes()) / totalDays;
Console.WriteLine("There is an average of {0} minutes of night over the past {1} days.", averageMinutes, totalDays);
But again. This is one of the ways of doing it. I would recommend you to get and read C# in Depth by Jon Skeet and also dive into the clean code principles.
Anyways, i think i have made myself clear. See example code for more details.
Good luck!

How to cycle through an (n by 12) 2D array

I have a 2-D array (with dimensions magnitudes n by 5), which I'm picturing in my head like this (each box is an element of the array):
(http://tr1.cbsistatic.com/hub/i/2015/05/07/b1ff8c33-f492-11e4-940f-14feb5cc3d2a/12039.jpg)
In this image, n is 3. I.e, n is the number of columns, 5 is the number of rows in my array.
I want to find an efficient way to iterate (i.e walk) through every path that leads from any cell in the left most column, to any cell in right most column, choosing one cell from every column in between.
It cannot be simply solved by n nested loops, because n is only determined at run time.
I think this means recursion is likely the best way forward, but can't picture how to begin theoretically.
Can you offer some advice as to how to cycle through every path. It seems simple enough and I can't tell what I'm doing wrong. Even just a theoretical explanation without any code will be very much appreciated.
I'm coding in C#, Visual Studio in case that helps.
UPDATE:: resolved using code below from http://www.introprogramming.info/english-intro-csharp-book/read-online/chapter-10-recursion/#_Toc362296468
static void NestedLoops(int currentLoop)
{
if (currentLoop == numberOfLoops)
{
return;
}
for (int counter=1; counter<=numberOfIterations; counter++)
{
loops[currentLoop] = counter;
NestedLoops(currentLoop + 1);
}
}
This is a factorial problem and so you might run quite quickly into memory or value limits issues.
Took some code from this SO post by Diego.
class Program
{
static void Main(string[] args)
{
int n = 5;
int r = 5;
var combinations = Math.Pow(r, n);
var list = new List<string>();
for (Int64 i = 1; i < combinations; i++)
{
var s = LongToBase(i);
var fill = n - s.Length;
list.Add(new String('0', fill) + s);
}
// list contains all your paths now
Console.ReadKey();
}
private static readonly char[] BaseChars = "01234".ToCharArray();
public static string LongToBase(long value)
{
long targetBase = BaseChars.Length;
char[] buffer = new char[Math.Max((int)Math.Ceiling(Math.Log(value + 1, targetBase)), 1)];
var i = (long)buffer.Length;
do
{
buffer[--i] = BaseChars[value % targetBase];
value = value / targetBase;
}
while (value > 0);
return new string(buffer);
}
}
list will contain a list of numbers expressed in base 5 which can be used to found out the path. for example "00123" means first cell, then first cell then second cell, then third cell and finall fourth cell.
Resolved:: see the code posted in the edited question above, and the link to a recursion tutorial, where it takes you through using recursion to simulate N nested, iterative loops.

Insert an underlying value into a non-existing index

I'm trying to solve a simple algorithm a specific way where it takes the current row and adds it to the top most row. I know there are plenty of ways to solve this but currently I have a text file that gets read line by line. Each line is converted to an sbyte (there's a certain reason why I am using sbyte but it's irrelevant to my post and I won't mention it here) and added to a list. From there, the line is reversed and added to another list. Here's the code I have for that first part:
List<List<sbyte>> largeNumbers = new List<List<sbyte>>();
List<string> total = new List<string>();
string bigIntFile = #"C:\Users\Justin\Documents\BigNumbers.txt";
string result;
StreamReader streamReader = new StreamReader(bigIntFile);
while ((result = streamReader.ReadLine()) != null)
{
List<sbyte> largeNumber = new List<sbyte>();
for (int i = 0; i < result.Length; i++)
{
sbyte singleConvertedDigit = Convert.ToSByte(result.Substring(i, 1));
largeNumber.Add(singleConvertedDigit);
}
largeNumber.Reverse();
largeNumbers.Add(largeNumber);
}
From there, I want to use an empty list that stores strings which I will be using later for adding my numbers. However, I want to be able to add numbers to this new list named "total". The numbers I'll be adding to it are not all the same length and because so, I need to check if an index exists at a certain location, if it does I'll be adding the value I'm looking at to the number that resides in that index, if not, I need to create that index and set it's value to 0. In trying to do so, I keep getting an IndexOutOfRange exception (obviously because that index doesn't exist). :
foreach (var largeNumber in largeNumbers)
{
int totalIndex = 0;
foreach (var digit in largeNumber)
{
if (total.Count == 0)
{
total[totalIndex] = digit.ToString(); //Index out of Range exception occurs here
}
else
{
total[totalIndex] = (Convert.ToSByte(total[totalIndex]) + digit).ToString();
}
totalIndex ++;
}
}
I'm just at a loss. Any Ideas on how to check if that index exists; if it does not create it and set it's underlying value equal to 0? This is just a fun exercise for me but I am hitting a brick wall with this lovely index portion. I've tried to use SingleOrDefault as well as ElementAtOrDefault but they don't seem to be working so hot for me. Thanks in advance!
Depending on if your result is have small number of missing elements (i.e. have more than 50% elements missing) consider simply adding 0 to the list till you reach neccessary index. You may use list of nullable items (i.e. List<int?>) instead of regular values (List<int>) if you care if item is missing or not.
Something like (non-compiled...) sample:
// List<long> list; int index; long value
if (index >= list.Count)
{
list.AddRange(Enumerable.Repeat(0, index-list.Count+1);
}
list[index] = value;
If you have significant number of missing elements use Dictionary (or SortedDictionary) with (index, value) pairs.
Dictionary<int, long> items;
if (items.ContainsKey(index))
{
items[key] = value;
}
else
{
items.Add(index, value);
}

Whats the most concise way to pick a random element by weight in c#?

Lets assume:
List<element> which element is:
public class Element {
int Weight { get; set; }
}
What I want to achieve is, select an element randomly by the weight.
For example:
Element_1.Weight = 100;
Element_2.Weight = 50;
Element_3.Weight = 200;
So
the chance Element_1 got selected is 100/(100+50+200)=28.57%
the chance Element_2 got selected is 50/(100+50+200)=14.29%
the chance Element_3 got selected is 200/(100+50+200)=57.14%
I know I can create a loop, calculate total, etc...
What I want to learn is, whats the best way to do this by Linq in ONE line (or as short as possible), thanks.
UPDATE
I found my answer below. First thing I learn is: Linq is NOT magic, it's slower then well-designed loop.
So my question becomes find a random element by weight, (without as short as possible stuff :)
If you want a generic version (useful for using with a (singleton) randomize helper, consider whether you need a constant seed or not)
usage:
randomizer.GetRandomItem(items, x => x.Weight)
code:
public T GetRandomItem<T>(IEnumerable<T> itemsEnumerable, Func<T, int> weightKey)
{
var items = itemsEnumerable.ToList();
var totalWeight = items.Sum(x => weightKey(x));
var randomWeightedIndex = _random.Next(totalWeight);
var itemWeightedIndex = 0;
foreach(var item in items)
{
itemWeightedIndex += weightKey(item);
if(randomWeightedIndex < itemWeightedIndex)
return item;
}
throw new ArgumentException("Collection count and weights must be greater than 0");
}
// assuming rnd is an already instantiated instance of the Random class
var max = list.Sum(y => y.Weight);
var rand = rnd.Next(max);
var res = list
.FirstOrDefault(x => rand >= (max -= x.Weight));
This is a fast solution with precomputation. The precomputation takes O(n), the search O(log(n)).
Precompute:
int[] lookup=new int[elements.Length];
lookup[0]=elements[0].Weight-1;
for(int i=1;i<lookup.Length;i++)
{
lookup[i]=lookup[i-1]+elements[i].Weight;
}
To generate:
int total=lookup[lookup.Length-1];
int chosen=random.GetNext(total);
int index=Array.BinarySearch(lookup,chosen);
if(index<0)
index=~index;
return elements[index];
But if the list changes between each search, you can instead use a simple O(n) linear search:
int total=elements.Sum(e=>e.Weight);
int chosen=random.GetNext(total);
int runningSum=0;
foreach(var element in elements)
{
runningSum+=element.Weight;
if(chosen<runningSum)
return element;
}
This could work:
int weightsSum = list.Sum(element => element.Weight);
int start = 1;
var partitions = list.Select(element =>
{
var oldStart = start;
start += element.Weight;
return new { Element = element, End = oldStart + element.Weight - 1};
});
var randomWeight = random.Next(weightsSum);
var randomElement = partitions.First(partition => (partition.End > randomWeight)).
Select(partition => partition.Element);
Basically, for each element a partition is created with an end weight.
In your example, Element1 would associated to (1-->100), Element2 associated to (101-->151) and so on...
Then a random weight sum is calculated and we look for the range which is associated to it.
You could also compute the sum in the method group but that would introduce another side effect...
Note that I'm not saying this is elegant or fast. But it does use linq (not in one line...)
.Net 6 introduced .MaxBy making this much easier.
This could now be simplified to the following one-liner:
list.MaxBy(x => rng.GetNext(x.weight));
This works best if the weights are large or floating point numbers, otherwise there will be collisions, which can be prevented by multiplying the weight by some factor.

What is the best way in linq to calculate the percentage from a list?

I have a list of 1s and 0s and I have to now calculate the percent meaning if 1 he achieved it else he doesn't. So e.g -
{1,1,0,0,0}
So for e.g If List has 5 items and he got 2 ones then his percent is 40%. Is there a function or way in LINQ I could do it easily maybe in one line ? I am sure LINQ experts have a suave way of doing it ?
What about
var list = new List<int>{1,1,0,0,0};
var percentage = ((double)list.Sum())/list.Count*100;
or if you want to get the percentage of a specific element
var percentage = ((double)list.Count(i=>i==1))/list.Count*100;
EDIT
Note BrokenGlass's solution and use the Average extension method for the first case as in
var percentage = list.Average() * 100;
In this special case you can also use Average() :
var list = new List<int> {1,1,0,0,0};
double percent = list.Average() * 100;
If you're working with any ICollection<T> (such as List<T>) the Count property will probably be O(1); but in the more general case of any sequence the Count() extension method is going to be O(N), making it less than ideal. Thus for the most general case you might consider something like this which counts elements matching a specified predicate and all elements in one go:
public static double Percent<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
int total = 0;
int count = 0;
foreach (T item in source)
{
++count;
if (predicate(item))
{
total += 1;
}
}
return (100.0 * total) / count;
}
Then you'd just do:
var list = new List<int> { 1, 1, 0, 0, 0 };
double percent = list.Percent(i => i == 1);
Output:
40
Best way to do it:
var percentage = ((double)list.Count(i=>i==1))/list.Count*100;
or
var percentage = ((double)list.Count(i=>i <= yourValueHere))/list.Count*100;
If You
want to do it in one line
don't want to maintain an extension method
can't take advantage of list.Sum() because your list data isn't 1s and 0s
you can do something like this:
percentAchieved = (int)
((double)(from MyClass myClass
in myList
where MyClass.SomeProperty == "SomeValue"
select myClass).ToList().Count /
(double)myList.Count *
100.0
);

Categories