Previous index in an array c# - c#

I have an array initialized as such:
int[] myArray = new int[] {9, 8, 7, 3, 4, 5, 6, 2, 1};
I then have a for() loop searching the array for the highest value each time using:
int maxValue = myArray.Max();
int maxIndex = myArray.ToList().IndexOf(maxValue);
It obviously keeps finding 9 as the highest value.
I want it to first set the previously indexed value to a randomized value below the current maxValue but above -1 and continue searching the array for the next maxValue and print it to console.
(If all values reach a value == 0 then the simulation stops) <- this part I know how to do.
Is this possible? If so, how?

I guess this might be what you want. Let me know how it works for you.
using System;
using System.Linq;
public class Program
{
private static Random random = new Random();
public static void Main()
{
int[] myArray = new int[] {9, 8, 7, 3, 4, 5, 6, 2, 1};
Simulate(myArray);
}
static void Simulate(int[] myArray)
{
int maxValue = myArray.Max();
Console.WriteLine(string.Join(" ",myArray));
var continueSimulation = true;
do{
int maxIndex = myArray.ToList().IndexOf(maxValue);
var randomValue = random.Next(0, maxValue);
myArray[maxIndex] = randomValue;
maxValue = myArray.Max();
if (maxValue == 0)
continueSimulation = false;
Console.WriteLine(string.Join(" ",myArray));
}while(continueSimulation);
}
}
You can check it out on this fiddle.
Hope this helps!

If you want to find the second max, you can mark the position of the first one and continue with your same approach. How can be done? 1- initialize an array of bool with the same length of the array where you want to find the max, then find the first max and mark that position in the second array with true, if you want the second max, make a loop through the array asking for the max and if that element is not marked in the second array of bool. Finally you will get the second max .
Another idea is taking the values in a list and once you find the max, remove the max from the list to continue with the same algorithm but with an array of less values
static int Max(int [] num)
{
int max = num[0];
for(int i = 0; i < num.Length; i ++)
{
if(num[i] > max)
max = num[i];
}
return max;
}
static int SecondMax(int[]a)
{
if(a.Length < 2) throw new Exception("....");
int count = 0;
int max = Max(a);
int[]b = new int[a.Length];
for(int i = 0; i < a.Length; i ++)
{
if(a[i] == max && count == 0)
{
b[i] = int.MinValue;
count ++;
}
else b[i] = a[i];
}
return Max(b);
}

Honestly, the question feels a bit unusual, so if you share why you're trying to do this, maybe someone could suggest a better approach. However, to answer your original question, you can just use .NET's random number generator.
int[] myArray = new int[] { 9, 8, 7, 3, 4, 5, 6, 2, 1 };
Random random = new Random();
for (int max = myArray.Max(); max > 0; max = myArray.Max())
{
int index = myArray.IndexOf(max);
DoSomething(max);
myArray[index] = random.Next(0, max);
}
From the MSDN doco on Random, the upper bound is exclusive, which means that it will generate a random number between 0 and max-1, unless max==0, in which case it will return 0.

Related

In this code how did we get the second largest element in an array

In the below code we are getting largest number by using this arr[Array.IndexOf(arr, maxNum)] = 0;
but we did nothing to get second largest number we just changed maxNum to secondMaxnum and passed the parameter of secondMaxNum in console.WriteLine and get the second largest number can anyone explain how is this happening..
var arr = new int[] { 2, 9, 1, 4, 6 };
var maxNum = arr[0];
foreach (var item in arr)
{
if (item > maxNum)
maxNum = item;
}
arr[Array.IndexOf(arr, maxNum)] = 0;
var secondMaxNum = arr[0];
foreach (var item in arr)
{
if (item > secondMaxNum)
secondMaxNum = item;
}
Console.WriteLine(secondMaxNum);
The two loops are basically doing the same thing, finding the largest number in the array. The important thing is what's happening between the two loops:
arr[Array.IndexOf(arr, maxNum)] = 0;
This is actually setting the largest value to zero, thereby making it less than all the other values. So that the previously second highest is now the highest.
Of course, this will only work for very specific data. If all the numbers in the array were negative for example, it would fail spectacularly.
It's also not the most efficient solution since it has three O(n) loops, the two explicit for loops and the implicit one in IndexOf. You would be better off storing the index during the first loop so you don't have to use IndexOf at all, something like:
var maxIdx = 0;
foreach (var i = 1; i < arr.Length; ++i)
if (arr[i] > arr[maxIdx])
maxIdx = i;
arr[maxIdx] = 0;
Array.IndexOf(arr, maxNum)
is getting the index of your highest number of 9 which is index 1;
arr[1] = 0;
You are setting the element with index 1 to the value 0;
var firstRun = new int[] { 2, 9, 1, 4, 6 };
var secondRun = new int[] { 2, 0, 1, 4, 6 };
you are doing the same thing in both loops.
AFTER the first loop you set the value of the highest number to 0.
so in the second look you get the highest number (which was the 2nd highest number before you set that the highest to 0)

Counting huge permutations - counting elements and getting nth element

I am using this library for combinatorics:
https://github.com/eoincampbell/combinatorics/
What I need is to find n-th permutation and count elements of fairly large sets (up to about 30 elements), but I get stopped in my tracks before even starting, check out this code:
int[] testSet = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21};
var permutation = new Permutations<int>(testSet);
var test = permutation.Count;
Everything works peachy just until 20 element large set, once I add 21st, permutations stop working right, eg.
here is what permutation.Count returns:
-4249290049419214848
which is far from being the right number.
I am assuming that it all boils down to how huge numbers I use - overflowing ints/longs that library uses. That is why, I am asking for an advice - is there a library? approach? or a fairly quick to implement way to have combinatorics work on bigintegers?
Thanks!
Get the number of possible permuations.
The number of permutations is defined by nPr or n over r
n!
P(n,r) = --------
(n - r)!
Where:
n = Number of objects
r = the size of the result set
In your example, you want to get all permutations of a given list. In this case n = r.
public static BigInteger CalcCount(BigInteger n, BigInteger r)
{
BigInteger result = n.Factorial() / (n - r).Factorial();
return result;
}
public static class BigIntExtensions
{
public static BigInteger Factorial(this BigInteger integer)
{
if(integer < 1) return new BigInteger(1);
BigInteger result = integer;
for (BigInteger i = 1; i < integer; i++)
{
result = result * i;
}
return result;
}
}
Get the nTh permutation
This one depends on how you create/enumerate the permutations. Usually to generate any permutation you do not need to know all previous permutations. In other words, creating a permutation could be a pure function, allowing you to directly create the nTh permutation, without creating all possible ones.
This, however, depends on the algorithms used. But will potentially be a lot faster to create the permutation only when needed (in contrast to creating all possible permutations up front -> performance and very memory heavy).
Here is a great discussion on how to create permutations without needing to calculate the previous ones: https://stackoverflow.com/a/24257996/1681616.
This is too long for a comment, but wanted to follow up on #Iqon's solution above. Below is an algorithm that retrieves the nth lexicographical permutation:
public static int[] nthPerm(BigInteger myIndex, int n, int r, BigInteger total)
{
int j = 0, n1 = n;
BigInteger temp, index1 = myIndex;
temp = total ;
List<int> indexList = new List<int>();
for (int k = 0; k < n; k++) {
indexList.Add(k);
}
int[] res = new int[r];
for (int k = 0; k < r; k++, n1--) {
temp /= n1;
j = (int) (index1 / temp);
res[k] = indexList[j];
index1 -= (temp * j);
indexList.RemoveAt(j);
}
return res;
}
Here is a test case and the result of calling nthPerm using the code provided by #Iqon.
public static void Main()
{
int[] testSet = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21};
BigInteger numPerms, n, r;
n = testSet.Length;
r = testSet.Length;
numPerms = CalcCount(n, r);
Console.WriteLine(numPerms);
BigInteger testIndex = new BigInteger(1234567890987654321);
int[] myNthIndex = nthPerm(testIndex, (int) n, (int) r, numPerms);
int[] myNthPerm = new int[(int) r];
for (int i = 0; i < (int) r; i++) {
myNthPerm[i] = testSet[myNthIndex[i]];
}
Console.WriteLine(string.Join(",", myNthPerm));
}
// Returns 1,12,4,18,20,19,7,5,16,11,6,8,21,15,13,2,14,9,10,17,3
Here is a link to ideone with working code.
You can useJNumberTools
List<String> list = new ArrayList<>();
//add elements to list;
JNumberTools.permutationsOf(list)
.uniqueNth(1000_000_000) //next 1 billionth permutation
.forEach(System.out::println);
This API will generate the next nth permutation directly in lexicographic order. So you can even generate next billionth permutation of 100 items.
for generating next nth permutation of given size use:
maven dependency for JNumberTools is:
<dependency>
<groupId>io.github.deepeshpatel</groupId>
<artifactId>jnumbertools</artifactId>
<version>1.0.0</version>
</dependency>

Using one variable to input 5 integers C#

I am using C# and i am trying to find the the average of 5 values but i can only use 2 variables.
How can you input 5 integers into one variable and display the average of said integers
You can use List like this:
var list = new List<int>(){ 1, 2, 3, 4, 5 };
var average = list.Average();
using Average you'll get average of all values in list
Here you have all functions of Enumerable, you can for e.g. sum all values with Sum
Use a collection like a List<int> and the extension method Enumerable.Average:
List<int> numbers = new List<int>{ 10, 20, 30, 40, 50 };
double average = numbers.Average(); // 30.0
Use List.Add to add single integers:
numbers.Add(1);
numbers.Add(2);
numbers.Add(3);
// ...
Take the input values in a Integer list or array then use the following code
List<int> intlist=new List<int>();
intlist.Add(2);
intlist.Add(3);
..
..
var average= intlist.Average();
Using Average will computes the average of a sequence of all the integers in the list.
UPDATE: or if the case is to use integers only then you need to use the following code (Remember to validate the readline() entries)
public decimal Average()
{
int value = 0;
for(int i=0;i<5;i++)
{
value+=ConvertToInt32(Console.ReadLine());
}
return value/5;
}
What about using array? I think array is one variable in your case
int[] input = new int[5];
input[0] = 5;
input[1] = 40;
input[2] = 15;
input[3] = 50;
input[4] = 25;
int sum = 0;
foreach(int i in input)
{
sum = sum + i;
}
sum = sum / input.Length;
Console.WriteLine(sum.ToString());
#up Yeah that's better way!
You dont need arrays, or lists or anything remotely similar. Pseudo-code:
private int sum = 0;
private int count = 0;
while (user inputs valid number)
{
sum += userInput;
count++;
}
return sum / count;
Only two variables.
If you just want solution without List<int> then here it is
int[] arr=new int[5];
arr[0]=10;arr[1]=20;...arr[4]=50;
int sum=0;
foreach(int x in arr)
{
s+=x;
}
s=s/arr.Length;//s is average
If you want list
List<int> list = new List<int>(){ 1, 2, 3, 4, 5 };
var average = list.Average();

How to generate random INT that cannot be a value in a List<int>?

I'm trying to do the following.
Let's say I have a List, and I want to generate a new int in a specific range, but the value cannot be already defined in the List.
List<int> PredefinedIntsList = new List<int>() { 1, 3, 4, 8, 9 };
Random rnd = new Random();
int NewRandomValue = rnd.Next(0, 10);
rnd.Next (obviously) comes up with 1, 3, 4, 8 or 9. But I ONLY want it to return 2, 5, 6, 7 or 10.
Any ideas?
As always, LINQ is your friend:
[TestMethod]
public void RandomTest()
{
var except = new[] {1, 2, 3, 5};
GetRandomExcept(1, 5, except).Should().Be(4);
}
private static int GetRandomExcept(int minValue, int maxValue, IEnumerable<int> except)
{
return GetRandoms(minValue, maxValue).Except(except).First();
}
private static IEnumerable<int> GetRandoms(int minValue, int maxValue)
{
var random = new Random();
while (true) yield return random.Next(minValue, maxValue);
}
Just keep in mind that you never should call GetRandoms().ToArray() or .Max() or .OrderBy() and so on, because you will get an endless loop and generate randoms forever.
What you can do though, is call GetRandoms().Take(10).ToArray() to get the next 10 random integers in an array.
Try examining if you can use the contains() method of List class... Simple solution would be to just generate values and checking contains and rejecting values that are already in the List until you get a value that is not. Also it might be more appropriate to use the Set Class because a set can not contain two elements that are equal.
What you need to do sample from other set. Lets say P is your predefinedIntsList and A is {1,2...9}.
You need to create a list, N = A-P. You will randomly sample from this set of numbers. It can be written more elegantly I suppose but see below example.
class Program
{
static void Main(string[] args)
{
List<int> predefinedIntsList = new List<int>() { 1, 3, 4, 8, 9 };
Random rnd = new Random();
List<int> newIntsList = new List<int>();
int upperBound = 10;
for (int i = 0; i < upperBound; i++)
{
if (!predefinedIntsList.Contains(i))
{
newIntsList.Add(i);
}
}
for (int i = 0; i < 20; i++)
{
int newRandomValueIndex = rnd.Next(0, newIntsList.Count);
int newRandomValue = newIntsList[newRandomValueIndex];
Console.WriteLine(newRandomValue);
}
}
}
Output
2
0
6
7
5
5
5
7
0
7
6
6
5
5
5
0
6
7
0
7
rnd.Next (obviously) comes up with 1, 3, 4, 8 or 9. But I ONLY want it
to return 2, 5, 6, 7 or 10.
Obviously not, it will return value that is either 0, 1, 2, 3, 4, 5, 6, 7, 8 or 9 :P. If you're looking to include 10, and not 0, you want .Next(1, 11)
There are two choices that can work: either try generating values until you succeed, or if the range is small enough, generate the range, mark elemens that can't be picked, and sort them to last ones, and then pick random between [0..possibleToPickElementsCount]
The first approach would look something like this:
public static class RandomExtensions
{
public static int Next(this Random random,
int minInclusive,
int maxExclusive,
IList<int> values)
{
// this will crash if values contains
// duplicate values.
var dic = values.ToDictionary(val => val);
// this can go into forever loop,
// think about this a bit.
for(;;){
var randomNumber= random.Next(minInclusive, maxExclusive);
if(!dic.ContainsKey(randomNumber))
return randomNumber;
}
}
}
The second approach is this, however it's only to give you an idea:
public static class RandomExtensions
{
class NormalizedPair
{
public int Value {get;set;}
public PairStatus Status {get;set;}
public NormalizedPair(int value){
Value = value;
}
public enum PairStatus {
Free,
NotFree
}
}
private static Random _internalRandom = new Random();
public static int Next(this Random random,
int minInclusive,
int maxExclusive,
IList<int> values)
{
var elements = maxExclusive - minInclusive;
var normalizedArr = new NormalizedPair[elements];
var normalizedMinInclusive = 0;
var normalizedMaxExclusive = maxExclusive - minInclusive;
var normalizedValues = values
.Select(x => x - minInclusive)
.ToList();
for(var j = 0; j < elements; j++)
{
normalizedArr[j] = new NormalizedPair(j){
Status = NormalizedPair.PairStatus.Free
};
}
foreach(var val in normalizedValues)
normalizedArr[val].Status = NormalizedPair.PairStatus.NotFree;
return normalizedArr
.Where(y => y.Status == NormalizedPair.PairStatus.Free) // take only free elements
.OrderBy(y => _internalRandom.Next()) // shuffle the free elements
.Select(y => y.Value + minInclusive) // project correct values
.First(); // pick first.
}
}
Or, if you're fan of sets:
public static int Next2(this Random random,
int minInclusive,
int maxExclusive,
IList<int> values)
{
var rangeSet = new HashSet<int>(
Enumerable.Range(
minInclusive,
maxExclusive - minInclusive));
// remove gibberish
rangeSet.ExceptWith(new HashSet<int>(values));
// this can be swapped out with
// yates shuffle algorithm
return rangeSet.OrderBy(x => _internalRandom.Next())
.First();
}
Rather than write logic to determine whether the random number has already been selected I prefer to generate a second list with the items in a random order.
That is easy to do with LINQ
var originalList = new List<int>() { 1, 3, 4, 8, 9 };
Random rnd = new Random();
var secondList = originalList.OrderBy(x=>rnd.NextDouble());
The call to rnd.NextDouble returns a random seed that is used by the OrderBy method to sort each int value.
When I need to run thought the randomized items more than once, with a new sort order each time I walk the list, I will use a Queue to store the items. Then dequeue the items as needed. When the queue is empty it's time to refill.
private Queue<int> _randomizedItems;
private void RandomTest()
{
var originalList = new List<int>() { 1, 3, 4, 8, 9 };
Random rnd = new Random();
var temp = originalList.OrderBy(r=>rnd.NextDouble());
_randomizedItems = new Queue<int>(temp);
while (_randomizedItems.Count >0)
{
MessageBox.Show(_randomizedItems.Dequeue().ToString());
}
}

inserting element into a list, if condition is met with C#

How to insert some number into the middle of the list, if there is no such number present?
In the example below I'm trying to insert number 4
List<int> list1 = new List<int>(){ 0, 1, 2, 3, 5, 6 };
int must_enter = 4;
if (!list1.Contains(must_enter))
{
list1.Add(must_enter);
}
As the result number will be entered at the end of the list, but I want it right after 3 (before 5).
please note that due to project's specifics I can't use sorted list, but all numbers in the list are guaranteed to be in ascending order (0,2,6,9,10,...)
EDIT: I knew about an error and that's what I did:
List<int> list0 = new List<int>() { 1, 2, 3, 5, 6 };
int must_enter = 7;
if (!list0.Contains(must_enter))
{
if (must_enter < list0.Max())
{
int result = list0.FindIndex(item => item > must_enter || must_enter > list0.Max());
list0.Insert(result, must_enter);
}
else
{
list0.Add(must_enter);
}
}
edit2: anyway I've switched to BinarySearch method due to several factors. Everyone thanks for your help!
You could do something like this:
int index = list1.BinarySearch(must_enter);
if (index < 0)
list1.Insert(~index, must_enter);
This way you will keep the list sorted with the best possible performance.
You can do:
list1.Add(must_enter);
And then order the list:
list1 = list1.OrderBy(n => n).ToList();
The result will be:
0, 1, 2, 3, 4, 5, 6
EDIT:
Or use an extesion method:
static class Utility
{
public static void InsertElement(this List<int> list, int n)
{
if(!list.Contains(n))
{
for(int i = 0; i < list.Count; i++)
{
if(list[i] > n)
{
list.Insert(i-1, n);
break;
}
if(i == list.Count - 1)
list.Add(n);
}
}
}
}
And then:
list1.InsertElement(must_enter);
You are looking for
list1.Insert(index, must_enter);
To insert an element at a specific index rather than at the end of the list.
You'll have to find the index to insert at first which is easily done with a binary search. Start with the value in the middle of the list and compare it to your number to insert. If it's greater, search the lower half of the list, if it's more, search the upper half of the list. Repeat the process, dividing the list in half each time until you find the spot where the item before is less than the one you are inserting and the item after is more than the one you are inserting. (edit: of course, if you list is always very small, it's probably less hassle just to iterate through the list from the beginning to find the right spot!)
List<int> list1 = new List<int>() { 0, 1, 2, 3, 5, 6 };
int must_enter = 4;
for (int i = 0; i < list1.Count; i++)
{
if (must_enter >= list1[i])
{
list1.Insert(i + 1, must_enter);
}
}
Edit: I like sarwar026, implementation better.
list1.Insert(4, 4)
List<T>.Insert Method - Inserts an element into the List at the specified index.
Quick Note-
the Insert instance method on the List type does not have good performance in many cases. because for Insert, list has to adjust the following elements.
here is the original post from where i got this answer try it out may help you : Finding best position for element in list
List<int> list = new List<int>{0,2,6,9,10};
for (int i = 0; i < list1.Count; i++)
{
int index = list.BinarySearch(i);
if( i < 0)
{
int insertIndex = ~index;
list.Insert(insertIndex, i);
}
}
just for one missing element as op needs
int index = list.BinarySearch(4);
if( index < 0)
{
int insertIndex = ~index;
list.Insert(insertIndex, 4);
}
or
List<int> list1 = new List<int>() { 0,2,6,9,10 };
int must_enter = 4;
for (int i = 0; i < list1.Count; i++)
{
if (!list1.Contains(i))
{
list1.Insert(i , i);
}
}
just for one element as op needs
if (!list1.Contains(4))
{
list1.Insert(4 , 4);
}
List<int> list1 = new List<int>(){ 0, 1, 2, 3, 5, 6 };
int must_enter = 4;
if (!list1.Contains(must_enter))
{
int result = list.FindIndex(item => item > must_enter);
if(result!=-1)
list1.Insert(result, must_enter);
else // must_enter is not found
{
if(must_enter > list.Max()) // must_enter > max value of list
list1.Add(must_enter);
else if(must_enter < list.Min()) // must_enter < min value of list
list1.Insert(0, must_enter);
}
}
First, find the index of the number which is greater than must_enter(4) and then insert the must_enter to that position
if (!list1.Contains(must_enter))
{
SortedSet<int> sorted = new SortedSet<int>( list1 );
sorted.Add( must_enter );
list1 = sorted.ToList();
}

Categories