I need to use a data structure that would keep the latest X elements of a list. A colleague gave me this solution:
int start = 0;
const int latestElementsToKeep = 20;
int[] numbers = new int[latestElementsToKeep];
for (int i = 0; i < 30; i++)
{
numbers[start] = i;
if (start < numbers.Length - 1)
{
start++;
}
else
{
start = 0;
}
}
So after this is run, the numbers array has numbers 19-29 (the latest 20 numbers).
That's nice, but difficult to use this in the real world. Is there an easier way to do this?
This seems like a pretty standard Circular Buffer. My only suggestion would be to create a class for it or download one of the libraries available. There seem to be a few promising looking ones near the top of the Google results.
Easier way to do this:
int[] numbers = new int[latestElementsToKeep];
for (int i = 0; i < 30; i++)
numbers[i % latestElementsToKeep] = i;
Modulus operator returns the reminder of dividing i by latestElementsToKeep. When i reaches latestElementsToKeep, you will start from the beginning.
For a range of numbers, you can use:
int keep = 20;
int lastItem = 29;
int[] numbers = Enumerable.Range(lastItem - keep, keep).ToArray();
To get the last items from any collection (where you can get the size), you can use:
int keep = 20;
someType[] items = someCollection.Skip(someCollection.Count() - keep).ToArray();
Related
I get Strings like this from my database:
NaN#Nan#44.20216139610997#45.35340149990988#45.44329482112824#45.1593428796393#NaN#NaN
values = SQLvalues.Split('#'); //produces Array you can see in the picture
(String[] values)
Going on further with strings until it ends with about 10 "NaN" Strings again.
What I am doing now is that I sum up all the values from that one Array.
But there will be about 100 more Arrays after this one and I need to add up for example values[8] from this Array with the one at the same position from the next Array.
hope this visualizes better what I need to do
As I am still an apprentice I don´t have much knowledge on all of this.
I´ve been trying to come with a solution for several hours now but I won´t seem to get anything to work here.
Any help would be great!
My Code:
String[] values;
String returnString = "";
List<Double> valueList = new List<Double>();
DateTime time = (DateTime)skzAdapterText.MinTambourChangedTime();
DataTable profilData = skzAdapterText.LoadValuesText(time);
int rowCount = profilData.Rows.Count;
for (int i = 0; i < rowCount; i++)
{
String SQLvalues = (String)profilData.Rows[i][2];
values = SQLvalues.Split('#');
double summe = 0;
int counter = 0;
foreach (String tmpRow in values)
{
Double value;
if (double.TryParse(tmpRow, NumberStyles.Float | NumberStyles.AllowThousands,
CultureInfo.InvariantCulture, out value)
&& !double.IsNaN(value))
{
counter++;
summe = summe + value;
}
}
if (summe != 0 && counter != 0)
valueList.Add(summe / counter);
}
The basic sum can be reduced like so:
values = SQLvalues.Split('#');
double sum = values.Where(v => v != "NaN").Select(v => double.Parse(v)).Sum();
For a specific position, say index 8, within many rows:
//Read the data from DB
DataTable profilData = skzAdapterText.LoadValuesText(time);
//parse out the values
var rowValueArrays = // will be a List<double[]>
profilData.Rows.
Select(r => r[2].Split('#').Select(v => v == "NaN"?0.0:double.Parse(v)).ToArray()).
ToList();
// sum the entries at index 8
double sumAt8 = rowValueArrays.Select(r => r[8]).Sum();
You say you are an apprentice, and so the syntax here may be unfamiliar to you and seem difficult to understand. But I want to emphasize the power here. The combination of IEnumerable, lambda expressions, and linq operations reduced the original sample down to two lines of code, and solved the full problem in what is technically three lines (spread out a little for readability). If I wanted to sacrifice any sense of style or maintainability, we could do it in just one line of code.
In short, it is well worth your time to learn how to write code this way. With practice, reading and writing code this way can become easy and greatly increase your speed and capability as a programmer.
I also see attempts to compute an average. Continuing from the end of the previous code:
int countAt8 = rowValuesArrays.Count(r => r[8] != 0.0);
double average = sumAt8 / countAt8;
Finally, I need to point out delimited data like this in a column is an abuse of the database and very poor practice. Schemas like this are considered broken, and need to be fixed.
As you want to sum up the values at the same positions of the arrays, I assume that all these array have the same length. Then first declare the required arrays. You also must probably calculate the average for each array position, so you also need an array for the counter and the averages.
double[] average = null;
int rowCount = profilData.Rows.Count;
if (rowCount > 0) {
string[] values = ((string)profilData.Rows[0][2]).Split('#');
int n = values.Length;
double[] sum = new double[n];
double[] counter = new double[n];
for (int i = 0; i < rowCount; i++) {
values = ((string)profilData.Rows[i][2]).Split('#');
for (int j = 0; j < n; j++) {
if (double.TryParse(values[j], NumberStyles.Float | NumberStyles.AllowThousands,
CultureInfo.InvariantCulture, out double value) && !double.IsNaN(value)) {
counter[j]++;
sum[j] += value;
}
}
}
average = new double[n];
for (int i = 0; i < n; i++) {
if (counter[i] != 0) {
average[i] = sum[i] / counter[i];
}
}
}
You cannot calculate the average while summing up, since you must divide the total sum by the total count. Therefore, I added another loop calculating the averages at each array position after the summing phase.
Well I'm trying to write a program in which if you add for example 3 integers in the array, let's say 3 2 1, it will add them again after it so it becomes 321 321.
Here is the code I need to fix. And sorry for the stupid question I am a beginner with arrays.
I get this error
Index was outside the bounds of the array
My code:
using System;
public class Program
{
public static void Main()
{
int arraylength = int.Parse(Console.ReadLine());
int[] array = new int[arraylength];
for (int i = 0; i < arraylength + 1 / 2; i++)
{
int typed = int.Parse(Console.ReadLine());
array[i] = typed;
if (i == arraylength / 2)
{
for (int a = arraylength + 1 / 2; a < arraylength + 1; a++)
{
array[a] = typed;
}
}
}
}
}
Array indices in C# start at 0 and end at length - 1. You need to remove the + 1 from each of your for loop conditions:
for (int i = 0; i < arraylenght / 2; i++)
and
for (int a = (arraylenght + 1) / 2; a < arraylenght; a++)
I also suggest that you change arraylenght to arraylength. Since you probably autocompleted this every time you used it, the misspelling occurs consistently throughout your code and the compiler is satisfied. However, misspellings make it difficult for humans to read your code.
p.s. Your code doesn't do what you think it does. I suggest you step away from the computer for a moment and write in words what you are trying to accomplish. Describe each step of your solution in as much detail as you can. Then look at how your words match with the code you wrote. You will probably find that you do not need nested loops.
i'm trying to get X number of random number (where X is a variable) between 0 and 100 and add them to a row in a DataGridView. I'm using the code below, but the problem is i need it to be impossible to have the same number twice. Is there a way make sure i get unique random numbers?
int X = 20;
Random random = new Random();
int randomrow = random.Next(0, 100);
for (int i = 0; i < X; i++)
{
int randomNumber = random.Next(0, 100);
data.Rows[randomrow][3] = randomNumber;
}
Thanks for the help!
Split your problem in two:
Create a list of X random, unique numbers. There are numerous ways to do that:
a. Create a list of all numbers 0-100 and then shuffle them. OR
b. Keep a hash set of all the numbers you already created (in addition to the list) and only add a new one if it has not been added before.
Afterwards, loop through the list and the data rows simultaneously and insert the values into the rows.
Here's the simple way to do it without creating a shuffle method for the List (though there are examples of that). Basically create a list of all possible integers, populate the list, then sort by new GUIDs.
int X = 20;
var RowNumbers = new List<int>();
for (int i = 0; i < X; i++)
RowNumbers.Add(i);
foreach (int i in RowNumbers.OrderBy(f => Guid.NewGuid()))
{
data.Rows[i][3] = i;
}
You would need to compare the numbers you have already used to the next one you get from random.Next. If you have already used it, pick another. I also like Heinzi's answer.
Here is algorithm without shuffling and previous result using:
var max = 100; // max available value
var count = 20; // number of random numbers
var random = new Random();
var rest = (double)max;
for (int i = 0; i < max; i++, rest--)
{
if (count / rest > random.NextDouble())
{
Console.WriteLine(i); // here is your random value
count--;
if (count == 0)
{
break;
}
}
}
I was having this discussion with my friend who had this question asked to him in the Interview. The Question goes like this. Write a Function which takes in a byte array(2 dimensional) as input along with an Integer n, The initial assumption is all the elements of M*N byte array is zero and the problem is to fill 'n' Byte array elements with value 1, For instance if M=5 and N=5 and the n value is 10 the Byte array should've 10/25 elements to be 1 and rest of the 15 values to be 0. The values filled should be random and one cell in byte array should be filled only once. I was fascinated to try solving this on my own. I've attached the code I've come up with so far.
public Boolean ByteArrayFiller(int a,int b, int n)
{
int count = n;
int iLocalCount = 0;
byte[,] bArray= new byte[a,b];
for (int i = 0; i <a; i++)
for (int j = 1; j <b; j++)
bArray[i, j] = 0;
Random randa= new Random();
int iRandA = randa.Next(a);
int iRandB = randa.Next(b);
while (iLocalCount < n)
{
if (bArray[iRandA, iRandB] == 0)
{
bArray[iRandA, iRandB] = 1;
iLocalCount++;
}
iRandA = randa.Next(a);
iRandB = randa.Next(b);
continue;
}
//do
//{
// //iRandA = randa.Next(a);
// //iRandB = randa.Next(b);
// bArray[iRandA,iRandB]=1;
// iLocalCount++;
//} while (iLocalCount<=count && bArray[iRandA,iRandB]==0);
return true;
}
The code i wrote is in C# but it's straight forward to understand. It's able to do the purpose of the question( I did some trials runs and results came out correctly) perfectly but I have used Random object in C#(Equivalent to Math.Rand in Java) to fill up the byte array and I keep thinking if Rand returns the same values for a and b. There is a good chance for this to go indefinitely. Is that the purpose of the question? or Does the solution that i came up for this question is good enough!
I am curious to see how experts here solve this problem? I am just looking for new ideas to expand my horizon. Any pointers would be greatly appreciated. Thanks for taking the time to read this post!
A while loop trying random locations until it finds a good one is generally a very bad approach. If n = M*N, then the last one will have a probability of 1/(M*N) of finding a match. If M*N are sufficiently large, this can be extremely inefficient.
If M*N is not too large, I would create a temporary array of M*N size, fill it with the numbers 0 through (M*N)-1, and then permutate it - i.e. you walk through it and swap the current value with that of a random other value.
Then you go to the first n elements in your array and set the appropriate cell. (row = value / columns, col = value % columns).
I would treat the array, logically, as a one-dimensional array. Fill the first n positions with the prescribed value, and then shuffle the array.
Given a byte array, and the number of rows and columns in the array, and assuming that the array is already filled with 0:
int NumElements = NumRows * NumCols;
for (int i = 0; i < NumElementsToFill; ++i)
{
int row = i / NumRows;
int col = i % NumCols;
array[row, col] = 1;
}
// Now shuffle the array
Random rnd = new Random();
for (int i = 0; i < NumElements; ++i)
{
int irow = i / NumRows;
int icol = i % NumCols;
int swapWith = rnd.Next(i+1);
int swapRow = swapWith / NumRows;
int swapCol = swapWith % NumCols;
byte temp = array[irow, icol];
array[irow, icol] = array[swapRow, swapCol];
array[swapRow, swapCol] = temp;
}
The key here is converting the one-dimensional index into row/col values. I used / and %. You could also use Math.DivRem. Or create Action methods that do the get and set for you.
Choose a number, which is larger than both N and M and is prime (or co-prime to both N and M). Let's call this number p.
Loop until you've set x numbers:
Generate a random number less than N*M. Call this number `l`.
Then the next place to put the number will be `p*l%(N*M)`, if that position hasn't been set.
A downside to this approach is that if the array is filling up, you'll have more collisions.
Bascially, you need to choose n unique random numbers from range [0, p) (where p = M * N), and map them to positions of 2-dimensional array.
Naive approaches are 1) generate non-unique numbers with retry 2) fill an array with numbers from 0 to p-1, shuffle it and take first n numbers (takes O(p) time, O(p) memory).
Another approach is to choose them with the following algorithm (O(n2) time, O(n) memory, code in Java):
public Set<Integer> chooseUniqueRandomNumbers(int n, int p) {
Set<Integer> choosen = new TreeSet<Integer>();
Random rnd = new Random();
for (int i = 0; i < n; i++) {
// Generate random number from range [0, p - i)
int c = rnd.nextInt(p - i);
// Adjust it as it was choosen from range [0, p) excluding already choosen numbers
Iterator<Integer> it = choosen.iterator();
while (it.hasNext() && it.next() <= c) c++;
choosen.add(c);
}
return choosen;
}
Mapping of generated numbers to positions of 2-dimensional array is trivial.
I wrote this code and its always showing the same results why?
The code is a searching method.
using System;
using System.Collections.Generic;
using System.Text;
namespace CArraySe
{
class Program
{
class CArray
{
private int[] arr;
private int upper;
private int numElements;
private int compCount;
public CArray(int size)
{
arr = new int[size];
upper = size - 1;
numElements = 0;
compCount = 0;
}
public void Insert(int item)
{
arr[numElements] = item;
numElements++;
}
public void DisplayElements()
{
for (int i = 0; i <= upper; i++)
{
Console.Write(arr[i]);
if (i == upper)
{
Console.WriteLine();
continue;
}
Console.Write(", ");
}
}
public void Clear()
{
for (int i = 0; i <= upper; i++)
arr[i] = 0;
numElements = 0;
}
public bool SeqSearch(CArray n, int sValue)
{
for (int index = 0; index < n.upper; index++)
{
if (arr[index] == sValue)
return true;
}
compCount++;
return false;
}
public int binSearch(CArray n, int value)
{
int upperBound, lowerBound, mid;
upperBound = n.upper; lowerBound = 0;
while (lowerBound <= upperBound)
{
mid = (upperBound + lowerBound) / 2;
if (arr[mid] == value)
return mid;
else if (value < arr[mid]) upperBound = mid - 1;
else lowerBound = mid + 1;
}
compCount++;
return -1;
}
static void Main(string[] args)
{
CArray nums = new CArray(10);
Random rnd = new Random(100);
for (int i = 0; i < 10; i++)
nums.Insert((int)(rnd.NextDouble() * 100));
Console.WriteLine();
Console.Write("The Binary Search Result is: ");
Console.WriteLine(nums.binSearch(nums, 500));
Console.WriteLine(nums.compCount);
nums.Clear();
for (int i = 0; i < 10; i++)
nums.Insert((int)(rnd.NextDouble() * 100));
Console.Write("The Sequential Search result is: ");
Console.WriteLine(nums.SeqSearch(nums, 500));
Console.WriteLine(nums.compCount);
}
}
}
}
Its always showing the same result even if I changed the number I'm looking for.
The output is:
The Binary Search Result is: -1
1
The Sequential Search result is: False
2
Press any key to continue . . .
I think your value being searched for (500) is not being found. Try outputting the nums array and verifying that what you are looking for is in the array.
Plus, one search returns an int and the other returns a bool. Is there a specific reason for that?
Edit: Also, Binary Search only works with sorted lists.
Your method binSearch returns "-1" when the number isn't found. Since you're populating your array with random values, the odds are very good that the number you search for won't be found. So you're always getting "-1".
To test your binSearch method, you should populate the array with known values, then search for some value that is guaranteed to be in the array.
The first answer is correct. Also, even though you are using a random number, each run of the program will produce the same sequence of random numbers. You should seed it with a different number each time you run the program if you want to test the code well.
As the others have already mentioned, in the general case, there's no guarantee that the number you're searching for is in the list of randomly generated numbers. In the specific case that you posted, the number will never appear in the list because you're generating random numbers in the 0-100 range, then trying to find 500.
Running what you provided does not add a value above 100. If you change your add to this:
for (int i = 0; i < 9; i++)
nums.Insert((int)(rnd.NextDouble() * 100));
nums.Insert(500);
The binSearch returns 9, but the SeqSearch return false because your looping search is index < n.upper and you need to do index <= n.upper to check all values. Additionally, as noted above, the binSearch only works in this case because 500 is larger than all the numbers in the array and has been placed at the last index. The binary search will only work by luck if the list its searching is not sorted. Therefore changing to:
nums.Insert(500);
for (int i = 0; i < 9; i++)
nums.Insert((int)(rnd.NextDouble() * 100));
Will return -1; and true for the SeqSearch.
Although this probably doesn't answer your question directly, here are some observations which makes your code hard to understand and debug:
You need either one of numElements or upper, not both. In Clear(), you are setting only numElements to 0 whereas you are using upper in your loops everywhere?
Binary search works only with sorted arrays
If SeqSearch and BinSearch are receiving an instance of the array, shouldn't they be static methods instead of instance methods?