Finding sequential Numbers - c#

I have a set of numbers List<int> (for example) : 1, 3, 4, 5, 7, 12, 13, 14, 15, 20, 22, 24, 28, 29, 30
I want to have them grouped as sequential like :
Sequence1 = from 1 amount 1 (1)
Sequence2 = from 3 amount 3 (3, 4, 5)
Sequence3 = from 7 amount 1 (7)
Sequence4 = from 12 amount 4 (12, 13, 14, 15)
Sequence5 = from 20 amount 1 (20)
Sequence6 = from 22 amount 1 (22)
Sequence7 = from 24 amount 1 (24)
Sequence8 = from 28 amount 3 (28, 29, 30)
I know how to do it with a for and checking for each number. Is there an more elegant way or an algorithm, or some sql/lambda command that would help me ?

If the input is sorted, and you really want to avoid a foreach loop, you can use:
list.Select((value,index)=>new {value,index}).GroupBy(x=>x.value-x.index,x=>x.value).Select(g=>g.AsEnumerable())
One could also write a general helper method:
public static IEnumerable<IEnumerable<T>> SplitBetween<T>(this IEnumerable<T> sequence, Func<T,T,bool> predicate)
{
T previous=default(T);
List<T> list=new List<T>();
int index=0;
foreach(T current in sequence)
{
if((index>0)&&predicate(previous,current))
{
yield return list.ToArray();
list.Clear();
}
list.Add(current);
previous=current;
index++;
}
if(list.Count>0)
yield return list.ToArray();
}
And then use it with list.SplitBetween((previous,current) => previous+1 != current)

I don't think that this is very "elegant", but here is my suggestion, hopefully it helps you:
var list = new List<int> { 1, 3, 4, 5, 7, 12, 13, 14, 15, 20, 22, 24, 28, 29, 30 };
int offset = 0;
int sequence = 0;
do
{
int offset1 = offset;
var subList = list.Skip(offset).TakeWhile((item, index) => (index == 0) || (item == (list[offset1 + index - 1] + 1))).ToList();
offset += subList.Count();
sequence++;
Debug.WriteLine("Sequence {0} from {1} amount {2} ({3})", sequence, subList[0], subList.Count(), string.Join(" ", subList));
}
while (offset < list.Count);

int n = 12;//your number
int x = list.IndexOf(n);
var result = list.Skip(x).TakeWhile((value, index) => value - index == n);

Related

Detecting consecutive integers and collapse to string

Disclaimer: A very similar question was already asked in a Python context here. This is about C#.
I have an enumeration containing integers such as:
[1, 2, 3, 4, 7, 8, 10, 11, 12, 13, 14]
I'd like to obtain a string putting out the ranges of consecutive integers:
1-4, 7-8, 10-14
I came up with:
public static void Main()
{
System.Diagnostics.Debug.WriteLine(FindConsecutiveNumbers(new int[] { 1,2, 7,8,9, 12, 15, 20,21 }));
}
private static string FindConsecutiveNumbers(IEnumerable<int> numbers)
{
var sb = new StringBuilder();
int? start = null;
int? lastNumber = null;
const string s = ", ";
const string c = "-";
var numbersPlusIntMax = numbers.ToList();
numbersPlusIntMax.Add(int.MaxValue);
foreach (var number in numbersPlusIntMax)
{
var isConsecutive = lastNumber != null && lastNumber + 1 == number;
if (!isConsecutive)
{
if (start != null)
{
if (sb.Length > 0) { sb.Append(s); }
if (start == lastNumber)
{
sb.Append(start); ;
}
else
{
sb.Append(start + c + lastNumber); ;
}
}
start = number;
}
lastNumber = number;
}
return sb.ToString();
}
This algorithm works for ordered input. Is there a built-in/LINQ/shorter C# way of doing this?
int[] numbers = { 1, 2, 3, 4, 7, 8, 10, 11, 12, 13, 14 };
return string.Join(", ",
numbers
.Select((n, i) => new { value = n, group = n - i })
.GroupBy(o => o.group)
.Select(g => g.First().value + "-" + g.Last().value)
);
I suggest decomposition: Let's split initial routine into logics:
private static IEnumerable<(int left, int right)> Consecutive(IEnumerable<int> numbers) {
int start = -1;
int stop = -2;
foreach (var item in numbers) // numbers.OrderBy(x => x) to sort numbers
if (item == stop + 1)
stop = item;
else {
if (stop >= start)
yield return (start, stop);
start = item;
stop = item;
}
if (stop >= start)
yield return (start, stop);
}
and representation
private static string FindConsecutiveNumbers(IEnumerable<int> numbers) =>
string.Join(", ", Consecutive(numbers)
.Select(item => item.left == item.right
? $"{item.left}"
: $"{item.left}-{item.right}"));
Then business as usual:
public static void Main()
{
// 1-2, 7-9, 12, 15, 20-21
System.Diagnostics.Debug.WriteLine(FindConsecutiveNumbers(new int[] {
1, 2,
7, 8, 9,
12,
15,
20, 21 }
));
}
If we could get the numbers in a List instead of an enumeration then we do not need to access all the numbers. The previous answers are have a time complexity of O(n) where n is the size of the array. Whereas if we have a list, this problem could be solved in O(klogn) where k is the number of groups.
Basically you could use a slightly modified binary search to find the end point of a group which could be done in O(logn) And then from end+1, you could do the same for the next group.

Int Array Reorder with Even Distribution in C#?

12,13,14,15,16,19,19,19,19
to
12,19,13,19,14,19,15,19,16
Hey all. Can anyone point me to clues/samples on how to distribute the first array of Int32 values, where a bunch of 19 values were appended, to the second where the 19 values are fairly evenly interspersed in the array?
I am not looking for a random shuffling, as in this example #19 could still appear consecutively if there was randomization. I want to make sure that #19 is placed in between the other numbers in a predictable pattern.
The use-case for this is something like teams taking turns presenting a topic: teams 12-16 each present once and then team #19 shows up but should not show their topic four times in a row, they should show their topic in between the other teams.
Later, if twelve values of 7 are added to the array, then they will also have to be evenly distributed into the sequence as well, the array would be 21 elements but the same rule that neither #19 or #7 should have consecutive showings.
I thought there might be something in Math.NET library that would do this, but I did not find anything. Using C# on .NET Framework 4.7.
Thanks.
Details on the following method that evenly (mostly) distributes the duplicates in your list. Duplicates can be anywhere in your list, they will be distributed.
Create a dictionary of all numbers and keep track of the number of times they appear in the list
Use a new list without any duplicates. For Each number that has duplicates, spread it over the size of this new list. Each time the distribution is even.
public static List<int> EvenlyDistribute(List<int> list)
{
List<int> original = list;
Dictionary<int, int> dict = new Dictionary<int, int>();
list.ForEach(x => dict[x] = dict.Keys.Contains(x) ? dict[x] + 1 : 1);
list = list.Where(x => dict[x] == 1).ToList();
foreach (int key in dict.Where(x => x.Value > 1).Select(x => x.Key))
{
int iterations = original.Where(x => x == key).Count();
for (int i = 0; i < iterations; i++)
list.Insert((int)Math.Ceiling((decimal)((list.Count + iterations) / iterations)) * i, key);
}
return list;
}
Usage in main:
List<int> test = new List<int>() {11,11,11,13,14,15,16,17,18,19,19,19,19};
List<int> newList = EvenlyDistribute(test);
Output
19,11,13,19,14,11,19,15,16,19,11,17,18
Here's how to do this.
var existing = new[] { 12, 13, 14, 15, 16 };
var additional = new [] { 19, 19, 19, 19 };
var lookup =
additional
.Select((x, n) => new { x, n })
.ToLookup(xn => xn.n * existing.Length / additional.Length, xn => xn.x);
var inserted =
existing
.SelectMany((x, n) => lookup[n].StartWith(x))
.ToArray();
This gives me results like 12, 19, 13, 19, 14, 19, 15, 19, 16.
The only thing that this won't do is insert a value in the first position, but otherwise it does evenly distribute the values.
In case random distribution is enough the following code is sufficient:
static void MixArray<T>(T[] array)
{
Random random = new Random();
int n = array.Length;
while (n > 1)
{
n--;
int k = random.Next(n + 1);
T value = array[k];
array[k] = array[n];
array[n] = value;
}
}
For instance:
int[] input = new int[]{12,13,14,15,16,19,19,19,19};
MixArray<int>(input);
In case you require precise evenly distribution while retaining the order of the elements, to following code will do the job:
public static T[] EvenlyDistribute<T>(T[] existing, T[] additional)
{
if (additional.Length == 0)
return existing;
if (additional.Length > existing.Length)
{
//switch arrays
T[] temp = additional;
additional = existing;
existing = temp;
}
T[] result = new T[existing.Length + additional.Length];
List<int> distribution = new List<int>(additional.Length);
double ratio = (double)(result.Length-1) / (additional.Length);
double correction = -1;
if (additional.Length == 1)
{
ratio = (double)result.Length / 2;
correction = 0;
}
double sum = 0;
for (int i = 0; i < additional.Length; i++)
{
sum += ratio;
distribution.Add(Math.Max(0, (int)(sum+correction)));
}
int existing_added = 0;
int additional_added = 0;
for (int i = 0; i < result.Length; i++)
{
if (additional_added == additional.Length)
result[i] = existing[existing_added++];
else
if (existing_added == existing.Length)
result[i] = additional[additional_added++];
else
{
if (distribution[additional_added] <= i)
result[i] = additional[additional_added++];
else
result[i] = existing[existing_added++];
}
}
return result;
}
For instance:
int[] existing = new int[] { 12, 13, 14, 15, 16};
int[] additional = new int[] { 101, 102, 103, 104};
int[] result = EvenlyDistribute<int>(existing, additional);
//result = 12, 101, 13, 102, 14, 103, 15, 104, 16

Consecutive points alternating up and down in a list

I have an observation list and want to find consecutive alternating up and down values for a given count. For example when observation list is { 1, 3, 4, 2, 7, 5, 6, 8, 1, 2, 4} and given count for check is 4, method should return a list<list>> as {{3,4,2,7}, {2,7,5,6}}.
I already create method as below, but want to do this with linq or more efficent way.Could anybody help?
List<List<decimal>> GetinvalidObservationMatrix(List<decimal> observationList, int checkedCount)
{
List<List<decimal>> invalidObservationMatrix = new List<List<decimal>>();
while (observationList.Count >= checkedCount)
{
List<decimal> currentObservationList = observationList.Take(checkedCount).ToList();
bool isGreater = false;
bool isPreviousGreater = false;
for (int i = 1; i < checkedCount - 1; i++)
{
isPreviousGreater = isGreater;
if (currentObservationList[i] == currentObservationList[i - 1] || currentObservationList[i] == currentObservationList[i + 1])
{
break;
}
if (currentObservationList[i] > currentObservationList[i - 1])
{
isGreater = true;
}
else
{
isGreater = false;
}
if (i != 1 && isGreater == isPreviousGreater)
{
break;
}
if (isGreater)
{
if (currentObservationList[i + 1] >= currentObservationList[i])
{
break;
}
}
else
{
if (currentObservationList[i + 1] <= currentObservationList[i])
{
break;
}
}
if (i == checkedCount - 2)
{
invalidObservationMatrix.Add(currentObservationList);
}
}
observationList = observationList.Skip(1).ToList();
}
return invalidObservationMatrix;
}
Accepting that this does not actually answer the original question, this code will find all the alternating sequences.
void FindAlternativeSequences()
{
var observations = new List<int>() { 1, 3, 4, 2, 7, 5, 6, 8, 1, 2, 4 };
const int threshold = 4;
var consecutivePairs = observations.Skip(1).Zip(observations, (a, b) => Math.Sign(a - b)).Zip(GetAlternator(), (x, y) => x * y);
var runs = FindEqualRuns(consecutivePairs).Select(t => new Tuple<int, int>(t.Item1, t.Item2 + 1)).ToList();
}
public IEnumerable<int> GetAlternator()
{
int value = -1;
int sanity = Int32.MaxValue;
while (--sanity > 0)
{
value *= -1;
yield return value;
}
yield break;
}
public IEnumerable<Tuple<int,int>> FindEqualRuns(IEnumerable<int> enumerable)
{
int previousValue = 0;
int index = 0;
int startIndex = 0;
bool foundAnElement = false;
foreach ( var value in enumerable )
{
if (index == 0) previousValue = value;
foundAnElement = true;
if (!value.Equals(previousValue))
{
// This is a difference, return the previous run
yield return new Tuple<int, int>(startIndex, index - startIndex);
startIndex = index;
previousValue = value;
}
index++;
}
if (foundAnElement)
{
yield return new Tuple<int, int>(startIndex, index - startIndex);
}
yield break;
}
What it does
The code finds all alternating sequences of any length, starting with either an up-step or a down-step. It then populates the runs variable with tuples where Item1 is the index of the first element in the sequence, and Item2 is the length of the alternating sequence.
This runs variable can then be used to ask a wide range of questions about the data, such as deriving the answer to the original question. The runs output by itself does not return the alternating sequences, but identifies where and how long they are.
How it works
The bulk of the of the work is done in one line:
var consecutivePairs = observations.Skip(1).Zip(observations, (a, b) => Math.Sign(a - b)).Zip(GetAlternator(), (x, y) => x * y);
This zips together the observations along with observations-skip-1 to give pairs of consecutive values. These pairs are then subtracted and run through the Math.Sign() function to give +1, -1 or 0 for whether the first is greater, the second is greater, or if they are the same. This output has runs of +1 or -1 for increasing or decreasing sequences. It's also one element shorter than observations.
observations => { 1, 3, 4, 2, 7, 5, 6, 8, 1, 2, 4 }
Output from 1st .Zip() => { 1, 1, -1, 1, -1, 1, 1, -1, 1, 1 }
This result is then zipped and multiplied by an alternating +1, -1, +1, -1, ... sequence. This results in runs of +1 or -1 indicating consecutive alternating up-steps and down-steps.
observations => { 1, 3, 4, 2, 7, 5, 6, 8, 1, 2, 4 }
Output from 1st .Zip() => { 1, 1, -1, 1, -1, 1, 1, -1, 1, 1 }
Output from 2nd .Zip() => { 1, -1, -1, -1, -1, -1, 1, 1, 1, -1 }
The line var runs = FindEqualRuns(consecutivePairs).Select(t => new Tuple<int, int>(t.Item1, t.Item2 + 1)).ToList(); then uses another function to find all the consecutive runs or either +1, -1, or 0 in that set, giving the startIndex and count. Because this gives us runs against the pairs enumeration (which is one element shorter than the original observations), we do need to add 1 to each count. For example, if it finds a run of 3 elements in the pairs enumeration, this represents a run of 4 elements in observations.
The output in runs gives the detail on the start and length of all the alternating sequences in the data.
runs => { {0, 2}, {1, 6}, {6, 4}, {9, 2} }
So there is:
a sequence of length 2, starting at the 0th index => { 1, 3 }
a sequence of length 6, starting at the 1st index => { 3, 4, 2, 7, 5, 6 }
a sequence of length 4, starting at the 6th index => { 6, 8, 1, 2 }
a sequence of length 2, starting at the 9th index => { 2, 4 }
Hope this helps

How can I find greatest number in array of number

I have an array like this
int[] intnumber = new int[]{10,25,12,36,100,54,68,75,63,24,1,6,9,5};
I want to find the greatest number and make it In order from largest to smallest
like this
100,75,68,63,54,36,25,24,12,10,9,6,5,1
int[] intnumber = new int[] { 10, 25, 12, 36, 100, 54, 68, 75, 63, 24, 1, 6, 9, 5 };
int maxValue = intnumber.Max();
You can sort the array for viewing elements in ascending order
Array.Sort(intnumber);
Array.Reverse(intnumber);
foreach (var str in intnumber )
{
MessageBox.Show(str.ToString());
}
Try this,
int[] intnumber = new int[] { 10, 25, 12, 36, 100, 54, 68, 75, 63, 24, 1, 6, 9, 5 };
//Maximum Value
int maxValue = intnumber.Max();
//Maximum Index
int maxIndex = intnumber.ToList().IndexOf(maxValue);
You can use :
int[] intnumber = new int[]{10,25,12,36,100,54,68,75,63,24,1,6,9,5};
Array.Sort(intnumber );
Array.Reverse(intnumber );
int max = intnumber[0];
exactly output that you want.
int[] intnumber = new int[] { 10,25,12,36,100,54,68,75,63,24,1,6,9,5 };
Array.Sort<int>(intnumber ,
new Comparison<int>(
(i1, i2) => i2.CompareTo(i1)
));
intnumber .Dump();
P.S. To run this demo you need to follow these steps:
1.Download LINQPad.
2.Download the demo file, open it with LINQPad and hit F5.
I found my answer with your helps
Console.WriteLine("How many Numbers Do you want? ");
int counter = int.Parse(Console.ReadLine());
double[] numbers = new double[counter];
for (int i = 0; i < numbers.Length; i++)
{
Console.Write((i + 1) + " : ");
numbers[i] = Convert.ToDouble(Console.ReadLine());
}
Console.WriteLine("_______________________________________________");
Array.Sort(numbers);
Array.Reverse(numbers);
foreach (double item in numbers)
{
Console.WriteLine(item);
}
Console.WriteLine("_______________________________________________");
Console.WriteLine("The Greatest Number is " + numbers[0]);
Console.ReadKey();
Let intNumbers be the array that you are using, Then you can use the .Max() method of the Array Class to get the maximum value, that is the greatest number. If you want to Sort the Current array means You have to use the .Sort() method. The requirement is simply Printing the Array in descending order means you have to use the .OrderBy()
int[] inputNumbers = new int[] { 15, 12, 11, 23, 45, 21, 2, 6, 85, 1 };
Console.WriteLine("Input Array is : {0}\n",String.Join(",",inputNumbers.OrderByDescending(x=>x)));
Console.WriteLine("Max value in the array is : {0}\n",inputNumbers.Max());
Console.WriteLine("Array in descending order : {0}\n",String.Join(",",inputNumbers.OrderByDescending(x=>x)));
Here is a working Example
int max = Integer.MIN_VALUE;
for (int i =0; i < intnumber.length; i++)
{
int num = intnumber[i];
//Check to see if num > max. If yes, then max = num.
}
System.out.println(max);

Acces a Row in a 2 dimensional array

I have a multidimentional array like this one with about 3000 rows and 200 columns:
+--+--+--+
|21|23|41|
+--+--+--+
|11|14|16| // 11 is the smalles value in 2nd row
+--+--+--+
|43|35|23|
+--+--+--+
I want to determine the smalles value of the second row.
Is there a better / more readable / linq solution? I currently use a for-loop?
My current Approach:
int min = array[0,1];
for (int i= 1; i<len;i++)
{
if (array[i,1] < min)
{
min = array[i,1];
}
}
Let arr be the array and l.u == 1 suggests second row:
arr.Select((t, u) => new { u, t }).Where(l => l.u == 1).FirstOrDefault().t.Min();
found a working solution
int[,] array = new int[3, 3] { { 21, 23, 41 }, { 11, 14, 16 }, { 43, 35, 23 } };
int min = Enumerable.Range(0, array.GetLength(1)).Min(i => array[1, i]);
Console.WriteLine(min); // 11

Categories