get "running average" of a list - c#

Say I've got a list:
List<int> numbers = new List<int>();
and I'm trying to get the "running averages" of it. (Sorry, I don't really know how to call it).
For instance:
The first item in this list is 5, the average of 5 is 5, so the first average is 5.
The second item in this list is 7, the average of 5 and 7 is 6, so the second average is 6.
The third item in this list is 10, the average of 5, 7 and 10 is 7.3, so the third average is 7.3
And so on.
Those first average, second average etc are the averages I'm trying to get. How would I go about doing this? I've been searching the internet but honestly I'm not quite sure what I should be looking for. :(

try this:
string st = Console.ReadLine();
string[] strs = st.Split(' ');
List<int> numbers = new List<int>();
List<double> averages = new List<double>();
for (int i = 0; i < strs.Length; i++)
{
numbers.Add(int.Parse(strs[i]));
averages.Add(numbers.Average());
}
this will read the numbers from the standard input, the numbers are separated by space in input.

You can try something like this:
var averages = Enumerable.Range(1, numbers.Count)
.Select(x => numbers.Take(x).Average())
.ToList();
This will generate a sequence from 1 to numbers.Count. Then using Take it will get X element at each time (you can think X as an index, only difference is it starts from 1 and increases one by one up to the numbers.Count) starting from the first element then get their average.Put them into a list.

The lists
List<int> numbers = new List<int>();
List<double> averages = new List<double>();
test data
numbers.AddRange(new int[]{5, 7, 10});
// get average of current List
averages.Add(numbers.Average());
Such a list of averages all by itself usually doesnt mean much without some other data like number of elements, duration of time or something to qualify it.
This method is better suited when the moving average is not one for one with the values. For instance, the app stores values. Then periodically, say once a minute, the average is calculated and stored.

You need the "Running Average", not the average from the start over all items I assume?
The running average needs a number to tell how far back to look and one to tell how far forward to look.
This will give you the running average:
public List<double> GetRunningAverage(List<double> SourceList, int ItemsBefore, int ItemsAfter)
{
List<double> TargetList = new List<double>() { };
// Only makes sense if the list is > 1 of course
if (SourceList.Count > 1)
{
for (int i = 0; i < SourceList.Count; i++)
{
int LookBack =
(ItemsBefore > i ? i : ItemsBefore);
int LookForward =
(ItemsAfter < SourceList.Count - i
? ItemsAfter : SourceList.Count - i);
TargetList.Add(SourceList.GetRange(i - LookBack, LookBack + LookForward).Average());
}
}
else
{
TargetList.AddRange(SourceList);
}
return TargetList;
}
You can then use it like this:
List<double> FullList = GetRunningAverage(
new List<double>() { 100, 5, 5, 6, 23, 10, 56, 32, 54, 1, 3, 85, 65, 49, 22, 65, 32, 5, 2, 4, 5, 89, 110, 55, 6, 56, 57 },
3, // Looking back 3 items
3); // Looking forward 3 items

Related

Efficiently adding multiple elements to the start of a List in C#

I have a list that I would like to add multiple elements to the start of. Adding to the start is linear time because it is backed by an array and has to be moved one at a time, and I cannot afford to do this as many times as I would have to if I implemented this the naive way.
If I know exactly how many elements I am about to add, can I shift them all that much so that the linearity only has to happen once?
List<int> myList = new List<int> { 6, 7, 8, 9, 10 };
//Desired list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
//Unacceptable
for (int i = 5; i>=0; i--){
myList.Insert(0,i);
}
//Is this concept possible?
int newElements = 5;
for (int i = myList.Count; i>=0; i--){
myList[i+newElements] = myList[i];//This line is illegal, Index was out of range
}
for (int i = 0; i< newElements; i++){
myList[i] = i+1;
}
In this specific instance, access needs to be constant time, hence the usage of List. I need to be able to add elements to both the start and end of the data structure as fast as possible. I am okay with O(m) where m is the number of elements being added (since I don't think that can be avoided) but O(m*n) where n is the number of elements in the existing structure is far too slow.
You can use InsertRange which will be linear if the inserted collection implements ICollection<T>:
var newElements = new[] { 0, 1, 2, 3, 4 };
myList.InsertRange(0, newElements);
myList.InsertRange(0, new List<int> { 1, 2, 3, 4, 5 });
If your new elements are already in a List, you could use List.AddRange to add your "old" list to the end of the to-be-added-items-list.
I would imagine myList.InsertRange(0, newElements) would suit you well. Microsoft will have made that as efficient as it can be.

Checking to see if last 2 numbers in array both exist in 2D array using loops

I have two arrays, one singular and the other 2 dimensional.
int[][] array1 = {
new int [] {1, 22, 3, 44, 5, 66},
new int [] {11, 22, 33, 44, 55, 66},
new int [] {1, 2, 3, 4, 5, 6},
};
int[] array2 = new int[] {1, 2, 3, 5, 66}
I need to create a loop which searches the array1 for both the 2nd last digits in array2, so it would return how many times an array with array1 contains both 5 and 66, which is 1, as the other two only contain 1 of each number.
I already managed to write a function which returns how many times array2 as a whole exists in array1, this new function is effectively a refinement of that.
for (int a = 0; a < array1[i].Length; a++)
{
for (int b = 0; b < array2.Length; b++)
{
if (array2[c] == array1[a][b])
count++;
temp[b] = array1[a][b];
}
}
I feel all would be needed to search for just the last two digits is a slight change to this function, I tried to add in another loop but that didn't work either. How would I go about doing this? I'm using loops and not Contains for a reason since i'm still learning the basics.
The one thing is not clear in question that, does it matter which position the two digits occur in the 2D array?
If ithis is not the case, then you can use Intersect() which produces the set intersection of two sequences by using the default equality comparer to compare values:
var result = array1.Count(x => x.Intersect(array2.Reverse().Take(2)).Count() == 2);
If you have paid an attention we have used this line, for getting last two elements of array1:
array1.Reverse().Take(2);
.NET Fiddle
Additional:
If you want to find if last two elements of arrays in 2D array is equal to last two elements of array1, then you can try LINQ solution:
var result = array1.Count(x=> x.Reverse().Take(2).SequenceEqual(array2.Reverse().Take(2)));
Explanation of used extension methods:
Reverse() inverts the order of the elements in a sequence.
Take() returns a specified number of contiguous elements from the start of a sequence.
SequenceEqual() determines whether two sequences are equal by comparing the elements by using the default equality comparer for their type.
After getting last two elements of both arrays, we will use SequenceEqual() to determine if both arrays are equal.
var res = array1.Where((x) => (x.Contains(array2.Last()) && x.Contains(array2[array2.Length - 2]))).Count();
Explaination:
array1.Where takes every subarray of array1 and filters the ones that
meet a certain condition. The condition being every subarray of
array1 contains the last && next-to-last element of array2.The
Count() methods returns the number of subarrays that meet the
conditions
You can create an array of target values and then count the number of times that the intersection of that array with each subarray in the 2D array contains all the items in the target array:
using System;
using System.Linq;
namespace ConsoleApplication2
{
class Program
{
[STAThread]
private static void Main()
{
int[][] array1 =
{
new [] {1, 22, 3, 44, 5, 66},
new [] {11, 22, 33, 44, 55, 66},
new [] {1, 2, 3, 4, 5, 6},
new [] {1, 66, 3, 4, 5, 6} // This one has the target items out of order.
};
int[] array2 = {1, 2, 3, 5, 66};
// Extract the targets like this; it avoids making a copy
// of array2 which occurs if you use IEnumerable.Reverse().
int[] targets = {array2[array2.Length - 2], array2[array2.Length - 1]};
// Count the number of times that each subarray in array1 includes
// all the items in targets:
int count = array1.Count(array => array.Intersect(targets).Count() == targets.Length);
Console.WriteLine(count);
}
}
}

Best way to lookup numbers in multiples of 3's C#

I'm currently working on a project that requires me to overwrite services.
I have 3 lists. List1, List2 and List3. I want all my lists to take care of any numbers in multiples of 3's.
A count will come in. If the number is 1 go to List 1. If the number is 4, go to List1. If the number is 9 go to List 3.
For example:
List1 will deal with 1, 4, 7, 10, 13, 16 etc
List2 will deal with 2, 5, 8, 11, 14, 17 etc
List3 will deal with 3, 6, 9, 12, 15, 18 etc
I hope that makes sense.
Rather than setting up tables or cases, I'd prefer a simple mathematical approach.
Thanks
You need to use modular maths. To do this you just need something like:
int listNumber = input % 3;
This will output 0, 1 or 2 for any positive integer. 0 will in this case represent list 3.
How you then use this will depend on how your Lists are stored, etc. but hopefully should be a simple exercise.
Simply use Modulus function. It returns remainder from division operation.
int number = 4;
int result = number % 3;
here result will be 1 which was required and so on.
This is best way to lookup numbers in multiples of 3's C#
var lists = new[] {
new List<int>(),
new List<int>(),
new List<int>()
};
var listToDoStuffWith = lists[inputNumber % 3];
Something like
var listSelector = number % 3;
switch(listSelector)
{
case 0:
list3.add(number);
break;
case 1:
list1.add(number);
break;
case 2:
list2.add(number);
break;
}
0 would land into list3 as 0 % 3 == 0

Sorting range of list using LINQ

I was wondering if it is possible to do ranged sort using LINQ, for example i have list of numbers:
List< int > numbers = new List< int >
1
2
3
15 <-- sort
11 <-- sort
13 <-- sort
10 <-- sort
6
7
etc.
Simply using numbers.Skip(3).Take(4).OrderBy(blabla) will work, but it will return a new list containing only those 4 numbers. Is is somehow possible to force LINQ to work on itself without returning a new "partial" list or to receive complete one with sorted part?
Thanks for any answer!
Try something like this:
var partiallySorted = list.Where(x => x < 11)
.Concat(list.Where(x => x >= 11 && x <=15).OrderBy(/*blah*/)))
.Concat(list.Where(x => x > 15));
List<int> list = new List<int>() {1,2,3,15,11,13,10,6,7};
list.Sort(3, 4,Comparer<int>.Default);
Simply get the required range based on some criteria and apply the sort on the resultant range using Linq.
List<int> numbers = new List<int>() { 15, 4, 1, 3, 2, 11, 7, 6, 12, 13 };
var range = numbers.Skip(3).Take(4).OrderBy(n => n).Select(s => s);
// output: 2, 3, 7, 11
No, the Linq extension methods will never modify the underlying list. You can use the method List<T>.Sort(int index, int counter, IComparer<T> comparer) to do an in-place sort:
var list = new List<int> {1, 2, 3, 15, 11, 13, 10, 6, 7};
list.Sort(3, 4, null);
Use this for default inline List Sort:
Syntax: List.Sort(start index, number of elements, Default Comparer)
List<int> numbers = new List<int> { 1, 2, 3, 15, 11, 13, 10, 6, 7 };
numbers.Sort(3, 6, Comparer<int>.Default);
If you want to sort by [properties/attributes] of the element or precisely something else use the below method,
I had sorted the string by number of characters, and also from 2nd element to end of List.
Syntax: List.Sort(start index, number of elements, Custom Comparer)
List<string> str = new List<string> { "123", "123456789", "12", "1234567" };
str.Sort(1, str.Count - 1, Comparer<string>.Create((x, y) => x.Length.CompareTo(y.Length)));

C# Calculate items in List<int> values vertically

I have a list of int values some thing like below (upper bound and lower bounds are dynamic)
1, 2, 3
4, 6, 0
5, 7, 1
I want to calculate the column values in vertical wise like
1 + 4 + 5 = 10
2 + 6 + 7 = 15
3 + 0 + 1 = 4
Expected Result = 10,15,4
Any help would be appreciated
Thanks
Deepu
Here's the input data using array literals, but the subsequent code works exactly the same on arrays or lists.
var grid = new []
{
new [] {1, 2, 3},
new [] {4, 6, 0},
new [] {5, 7, 1},
};
Now produce a sequence with one item for each column (take the number of elements in the shortest row), in which the value of the item is the sum of the row[column] value:
var totals = Enumerable.Range(0, grid.Min(row => row.Count()))
.Select(column => grid.Sum(row => row[column]));
Print that:
foreach (var total in totals)
Console.WriteLine(total);
If you use a 2D array you can just sum the first, second,... column of each row.
If you use a 1D array you can simply use a modulo:
int[] results = new results[colCount];
for(int i=0, i<list.Count; list++)
{
results[i%colCount] += list[i];
}
Do you have to use a "List"-object? Elseway, I would use a twodimensional array.
Otherwise, you simply could try, how to reach rows and columns separatly, so you can add the numbers within a simply for-loop. It depends on the methods of the List-object.
Quite inflexible based on the question, but how about:
int ans = 0;
for(int i = 0; i < list.length; i+=3)
{
ans+= list[i];
}
You could either run the same thing 3 times with a different initial iterator value, or put the whole thing in another loop with startValue as an interator that runs 3 times.
Having said this, you may want to a) look at a different way of storing your data if, indeed they are in a single list b) look at more flexible ways to to this or wrap in to a function which allows you to take in to account different column numbers etc...
Cheers,
Adam

Categories