Related
What I need is:
e.g:
Sum should be equal to:
120 (user input)
Number of numbers/items:
80 (user input)
Range of numbers to be used in set(from):
0 (user input)
Range of numbers to be used in set(to):
4 (user input)
Output:
1,1,3,2,1,1,0,0,1,1,2,1,0,2,3,3,1,2,0,0,0,1,3,2,3,1,0,0,2,3,2,3,2,2,1,1,0,0,2,0,1,0,1,1,3,3,1,3,1,0,0,3,2,1,0,0,2,1,2,3,0,3,1,1,3,3,2,2,1,1,3,1,3,3,3,3,3,1,2,0
These are all numbers that are between 0 and 4, their sum is 120 and are 80 in total.
What i've done is:
static void Main(string[] args)
{
bool loopOn = true;
Program p = new Program();
Console.WriteLine("____________________________________________________________________________");
Console.WriteLine("");
Console.WriteLine("Sum should be equal to:");
int sum = int.Parse(Console.ReadLine());
Console.WriteLine("Number of items:");
int items = int.Parse(Console.ReadLine());
Console.WriteLine("Range(from):");
int from = int.Parse(Console.ReadLine());
Console.WriteLine("Range(to):");
int to = int.Parse(Console.ReadLine());
while (loopOn == true)
{
List<int> number_list = p.createNumberSet(items, from, to);
if (number_list.Sum() == sum)
{
loopOn = false;
Console.WriteLine("____________________________________________________________________________");
Console.WriteLine("Start");
number_list.ForEach(Console.WriteLine);
Console.WriteLine("Stop");
Console.WriteLine("____________________________________________________________________________");
}
}
Console.WriteLine("Press any key to exit....");
Console.ReadLine();
}
public List<int> createNumberSet(int itemNumber, int range_from, int range_to)
{
List<int> number_set = new List<int>();
Random r = new Random();
for (int i = 0; itemNumber > i; i++)
{
number_set.Add(r.Next(range_from, range_to));
}
return number_set;
}
But this seems extremely in-efficent and doesn't seem to work with a lot of other examples. Does anyone have a better way of doing this?
Well, I am a bit lazy right now, so this is just an idea
Keep the first part:
bool loopOn = true;
Program p = new Program();
Console.WriteLine("____________________________________________________________________________");
Console.WriteLine("");
Console.WriteLine("Sum should be equal to:");
int sum = int.Parse(Console.ReadLine());
Console.WriteLine("Number of items:");
int items = int.Parse(Console.ReadLine());
Console.WriteLine("Range(from):");
int from = int.Parse(Console.ReadLine());
Console.WriteLine("Range(to):");
int to = int.Parse(Console.ReadLine());
Now, first of all, check is a solution exists:
if (from * items > sum) {
// There is no solution, handle accordingly
}
Let's focus on the interesting part now:
First create the list of necessary items
int[] number_set = new int[items];
for(int i = 0; i < items; i++) {
number_set[i] = from;
}
Find the difference between the wanted sum and the current sum of the list
int left_to_add = sum - from * items;
int idx = 0;
Random r = new Random();
while(left_to_add > 0) {
int toAdd = 0;
if (left_to_add < range_to - range_from) {
toAdd = r.Next(1, left_to_add);
} else {
toAdd = r.Next(1, range_to - range_from);
}
left_to_add -= toAdd;
number_set[idx] += toAdd;
idx++;
}
What's left to do is, convert the array to a list and shuffle it.
(I forgot that you actually can access list items by index, so there is no need to use an array as I did here)
At the algorithm level, this is what I would try:
Determine the number of each element, n[0], n[1], n[2], n[3] in your example (i.e. number of 0, number of 1 ...) and then generate a simple sequence by concatenating n[0] "0", n[1] "1", n[2] "2" and n[3] "3". Finally, a random sequence is obtained by performing a random permutation on this simple sequence.
The problem is therefore to determine the n[i].
The first step is to determine the average values of these n[i]. It your example, it is simple, as we can take average n_av[i]=20 for all index i.
In a more general case, we have to insure that
sum_i n_av[i]*i = sum_target (120 here) (1)
knowing that
sum_i (n[i]) = n = 80 here. (2)
In the general case, there is no necessary one unique good solution. I will try to propose an example of solution here if you provide an example of a difficult scenario.
The second step consists in selecting some random n[i] values around these average values. One possibility is to generate rounded Gaussian variables: we already know the averages, we just need to determine the variances. One possibility is to consider the variance that we will get if we were generating directly the random values, i.e. by considering the variance of the corresponding binomial variable :
var = n p(1-p). Here p[i] = n_av[i]/n
The last step consists in adjusting the values of the n[i] such that the sum of the n[i] is equal to the target. This is simply obtained by slightly increasing or decreasing some n[i] values.
Hi I'm a little bit stuck in C#. I'm new on it.
This is my problem:
I have a list made up of 63 double numbers (let's call it "big list").
I want to split this list in 6 list with the following rule:
The first list consists of the first 8 elements of the big list;
The second list goes from the 9th element of the big list to the (9+8=17th) element of the big list;
The third list goes from the 18th element of the big list to the (18+8+1=27th) element of the big list;
The fourth list goes from the 28th element of the big list to the (28+8+2=38th) element of the big list;
The fifth list goes from the 39th element of the big list to the (39+8+3=50th) element of the big list;
The sixth list goes from the 51th element of the big list to the (51+8+4=63th) element of the big list;
How can I do it? thanks a lot in advance for your help!
i've tried in this way but it gives me error "cannot apply indexing with [] to an expression of type method group"
List listsplitted = new List();
for (int i = 0; i < 6; i++)
{
for (int j = 8; j < 8 + i + 1; j++)
{
Listsplitted[i] = biglist.Take[j];
}
}
It is a very simple approach with the IEnumerable extensions Skip and Take
List<double> first = bigList.Take(8).ToList();
List<double> second = bigList.Skip(8).Take(8).ToList();
List<double> third = bigList.Skip(16).Take(9).ToList();
List<double> fourth = bigList.Skip(25).Take(10).ToList();
List<double> fifth = bigList.Skip(35).Take(11).ToList();
// The last one is without Take to get every remaining element
List<double> sixth = bigList.Skip(46).ToList();
Of course you should check if the indexes are correct for your requirements. These indexes doesn't skip any elements from your bigList
You can make this approach more generic with something like this
void Main()
{
var bigList = GetYourBigList();
List<Tuple<int, int>> positions = new List<Tuple<int, int>>
{
new Tuple<int, int>(0,8),
new Tuple<int, int>(8,8),
new Tuple<int, int>(16,9),
new Tuple<int, int>(25,10),
new Tuple<int, int>(35,11),
new Tuple<int, int>(46,13)
};
List<List<int>> result = SplitTheList(bigList, positions);
foreach (var list in result)
{
foreach (var temp in list)
Console.WriteLine(temp);
Console.WriteLine("--------------------");
}
}
List<List<int>> SplitTheList(List<int> r, List<Tuple<int, int>> positions)
{
List<List<int>> result = new List<List<int>>();
foreach(var x in positions)
result.Add(r.Skip(x.Item1).Take(x.Item2).ToList());
return result;
}
You can do it using GetRange function:
List<double> part1= big_list.GetRange(0, 8);//Retrieves 8 items starting with index '0'
List<double> part2= big_list.GetRange(8, 9);//Retrieves 9 items starting with index '8'
Or if you don't want to give different names to all parts, you can create a list of lists:
List<List<double>> listoflists = new List<List<double>>();
listoflists.Add(big_list.GetRange(0, 8));//Retrieves 8 items starting with index '0'
listoflists.Add(big_list.GetRange(8, 9));//Retrieves 9 items starting with index '8'
for(int i=0; i<listoflists.Count;i++){
for(int j=0; j<listoflists[i].Count; j++){
Console.Write(listoflists[i][j] + " ");
}
Console.WriteLine();
}
if you are insisting on do the operation in one single for statement you can use the following code
const int arrSize = 6;
var splitedLists = new List<List<int>>(arrSize);
var defaultTake = 8;
var defaultSkip = 0;
for (var i = 1; i <= arrSize; i++)
{
if (i >= 3)
defaultSkip--;
splitedLists.Add(array.Skip(defaultSkip).Take(defaultTake + 1).ToList());
if (i >= 2)
defaultTake++;
defaultSkip = defaultSkip + defaultTake + 1;
}
If you can replace the list with an array, you can do without copying the data. You can use ArraySegment (or Span/Memory in newer versions of the language) to do this.
var array = Enumerable.Range(0, 63).Select(i => (double)i).ToArray();
var splitted = new List<ArraySegment<double>>();
int offset = 0;
int count = 8;
for (int i = 0; i < 6; i++)
{
splitted.Add(new ArraySegment<double>(array, offset, count));
offset += count;
count++;
}
// see what we have
foreach (var seg in splitted)
Console.WriteLine(seg.Offset + " " + seg.Count);
// work with segments
var segment = splitted[3];
segment[5] = 555555;
// the main array has also changed
Console.WriteLine(string.Join(" ", array));
Note that the segments do not store copies of the data, but refer to the data in the main array.
I'm not sure if this has been asked before but I couldn't see it anywhere.
Can you loop an array? For example:
string[] = array1;
int num1 = 1;
do
{
lbl1.Text = array1[0]
}while(num1 = 1);
How can I make it so it adds one to the element every loop.
I agree that you need to better explain what you're trying to accomplish. If you hardcode num1 then perform a while num1 is equal to its initial value without ever modifying it, you're going to have an indefinite loop. In your example, it will just keep overwriting lbl1 to display the first item in your array.
By "add one to the element every loop", do you mean add each item in the array to your label? Try something like...
foreach (string item in array1)
{
lbl1.Text += array1[item];
}
Otherwise, please provide further details on what you're looking for.
It is really not clear what You want to achieve, but maybe this will get You nearer to the goal:
int[] array1 = new [] {0};
int num1 = 1;
do {
lbl1.Text = (array1[0]++).ToString();
num1++;
} while (num1 < 9);
or
int[] array1 = new [] {0};
for (int i = 0; i < 9; i++) {
lbl1.Text = (array1[0]++).ToString();
}
Not sure what you are trying to accomplish but the following is a stab at a solution
private static void foo(string[] array1)
{
if (array1 != null && array1.Length > 0)
{
for (int num1 = 0; num1 < array1.Length; num1++)
{
string doSomethingWithArrayElement = array1[num1];
}
}
}
I have a comma delimited text file that contains 20 digits separated by commas. These numbers represent earned points and possible points for ten different assignments. We're to use these to calculate a final score for the course.
Normally, I'd iterate through the numbers, creating two sums, divide and be done with it. However, our assignment dictates that we load the list of numbers into two arrays.
so this:
10,10,20,20,30,35,40,50,45,50,45,50,50,50,20,20,45,90,85,85
becomes this:
int[10] earned = {10,20,30,40,45,50,20,45,85};
int[10] possible = {10,20,35,50,50,50,20,90,85};
Right now, I'm using
for (x=0;x<10;x++)
{
earned[x] = scores[x*2]
poss [x] = scores[(x*2)+1]
}
which gives me the results I want, but seems excessively clunky.
Is there a better way?
The following should split each alternating item the list into the other two lists.
int[20] scores = {10,10,20,20,30,35,40,50,45,50,45,50,50,50,20,20,45,90,85,85};
int[10] earned;
int[10] possible;
int a = 0;
for(int x=0; x<10; x++)
{
earned[x] = scores[a++];
possible[x] = scores[a++];
}
You can use LINQ here:
var arrays = csv.Split(',')
.Select((v, index) => new {Value = int.Parse(v), Index = index})
.GroupBy(g => g.Index % 2,
g => g.Value,
(key, values) => values.ToArray())
.ToList();
and then
var earned = arrays[0];
var possible = arrays[1];
Get rid of the "magic" multiplications and illegible array index computations.
var earned = new List<int>();
var possible = new List<int>();
for (x=0; x<scores.Length; x += 2)
{
earned.Add(scores[x + 0]);
possible.Add(scores[x + 1]);
}
This has very little that would need a text comment. This is the gold standard for self-documenting code.
I initially thought the question was a C question because of all the incomprehensible indexing. It looked like pointer magic. It was too clever.
In my codebases I usually have an AsChunked extension available that splits a list into chunks of the given size.
var earned = new List<int>();
var possible = new List<int>();
foreach (var pair in scores.AsChunked(2)) {
earned.Add(pair[0]);
possible.Add(pair[1]);
}
Now the meaning of the code is apparent. The magic is gone.
Even shorter:
var pairs = scores.AsChunked(2);
var earned = pairs.Select(x => x[0]).ToArray();
var possible = pairs.Select(x => x[1]).ToArray();
I suppose you could do it like this:
int[] earned = new int[10];
int[] possible = new int[10];
int resultIndex = 0;
for (int i = 0; i < scores.Count; i = i + 2)
{
earned[resultIndex] = scores[i];
possible[resultIndex] = scores[i + 1];
resultIndex++;
}
You would have to be sure that an equal number of values are stored in scores.
I would leave your code as is. You are technically expressing very directly what your intent is, every 2nd element goes into each array.
The only way to improve that solution is to comment why you are multiplying. But I would expect someone to quickly recognize the trick, or easily reproduce what it is doing. Here is an excessive example of how to comment it. I wouldn't recommend using this directly.
for (x=0;x<10;x++)
{
//scores contains the elements inline one after the other
earned[x] = scores[x*2] //Get the even elements into earned
poss [x] = scores[(x*2)+1] //And the odd into poss
}
However if you really don't like the multiplication, you can track the scores index separately.
int i = 0;
for (int x = 0; x < 10; x++)
{
earned[x] = scores[i++];
poss [x] = scores[i++];
}
But I would probably prefer your version since it does not depend on the order of the operations.
var res = grades.Select((x, i) => new {x,i}).ToLookup(y=>y.i%2, y=>y.x)
int[] earned = res[0].ToArray();
int[] possible = res[1].ToArray();
This will group all grades into two buckets based on index, then you can just do ToArray if you need result in array form.
here is an example of my comment so you do not need to change the code regardless of the list size:
ArrayList Test = new ArrayList { "10,10,20,20,30,35,40,50,45,50,45,50,50,50,20,20,45,90,85,85" };
int[] earned = new int[Test.Count / 2];
int[] Score = new int[Test.Count / 2];
int Counter = 1; // start at one so earned is the first array entered in to
foreach (string TestRow in Test)
{
if (Counter % 2 != 0) // is the counter even
{
int nextNumber = 0;
for (int i = 0; i < Score.Length; i++) // this gets the posistion for the next array entry
{
if (String.IsNullOrEmpty(Convert.ToString(Score[i])))
{
nextNumber = i;
break;
}
}
Score[nextNumber] = Convert.ToInt32(TestRow);
}
else
{
int nextNumber = 0;
for (int i = 0; i < earned.Length; i++) // this gets the posistion for the next array entry
{
if (String.IsNullOrEmpty(Convert.ToString(earned[i])))
{
nextNumber = i;
break;
}
}
earned[nextNumber] = Convert.ToInt32(TestRow);
}
Counter++
}
I would like to programmatically add or remove some elements to a string array in C#, but still keeping the items I had before, a bit like the VB function ReDim Preserve.
The obvious suggestion would be to use a List<string> instead, which you will have already read from the other answers. This is definitely the best way in a real development scenario.
Of course, I want to make things more interesting (my day that is), so I will answer your question directly.
Here are a couple of functions that will Add and Remove elements from a string[]...
string[] Add(string[] array, string newValue){
int newLength = array.Length + 1;
string[] result = new string[newLength];
for(int i = 0; i < array.Length; i++)
result[i] = array[i];
result[newLength -1] = newValue;
return result;
}
string[] RemoveAt(string[] array, int index){
int newLength = array.Length - 1;
if(newLength < 1)
{
return array;//probably want to do some better logic for removing the last element
}
//this would also be a good time to check for "index out of bounds" and throw an exception or handle some other way
string[] result = new string[newLength];
int newCounter = 0;
for(int i = 0; i < array.Length; i++)
{
if(i == index)//it is assumed at this point i will match index once only
{
continue;
}
result[newCounter] = array[i];
newCounter++;
}
return result;
}
If you really won't (or can't) use a generic collection instead of your array, Array.Resize is c#'s version of redim preserve:
var oldA = new [] {1,2,3,4};
Array.Resize(ref oldA,10);
foreach(var i in oldA) Console.WriteLine(i); //1 2 3 4 0 0 0 0 0 0
Don't use an array - use a generic List<T> which allows you to add items dynamically.
If this is not an option, you can use Array.Copy or Array.CopyTo to copy the array into a larger array.
Since arrays implement IEnumerable<T> you can use Concat:
string[] strArr = { "foo", "bar" };
strArr = strArr.Concat(new string[] { "something", "new" });
Or what would be more appropriate would be to use a collection type that supports inline manipulation.
Use List<string> instead of string[].
List allows you to add and remove items with good performance.
What's abaut this one:
List<int> tmpList = intArry.ToList();
tmpList.Add(anyInt);
intArry = tmpList.ToArray();
One liner:
string[] items = new string[] { "a", "b" };
// this adds "c" to the string array:
items = new List<string>(items) { "c" }.ToArray();
You should take a look at the List object. Lists tend to be better at changing dynamically like you want. Arrays not so much...
You can use a generic collection, like List<>
List<string> list = new List<string>();
// add
list.Add("element");
// remove
list.Remove("element");
You can use this snippet:
static void Main(string[] args)
{
Console.WriteLine("Enter number:");
int fnum = 0;
bool chek = Int32.TryParse(Console.ReadLine(),out fnum);
Console.WriteLine("Enter number:");
int snum = 0;
chek = Int32.TryParse(Console.ReadLine(),out snum);
Console.WriteLine("Enter number:");
int thnum = 0;
chek = Int32.TryParse(Console.ReadLine(),out thnum);
int[] arr = AddToArr(fnum,snum,thnum);
IOrderedEnumerable<int> oarr = arr.OrderBy(delegate(int s)
{
return s;
});
Console.WriteLine("Here your result:");
oarr.ToList().FindAll(delegate(int num) {
Console.WriteLine(num);
return num > 0;
});
}
public static int[] AddToArr(params int[] arr) {
return arr;
}
I hope this will help to you, just change the type