Custom sorting array - smaller values between larger values - c#

I have an array A with values: {10, 12, 6, 14, 7} and I have an array B with values: {1, 8, 2}
I have sorted the array B in an ascending order and then combined both the arrays in a new array C as shown in the following code -
static void Main()
{
int A[] = {10, 12, 6, 14, 7};
int B[] = {1, 8, 2};
Array.Sort(B);
var myList = new List<int>();
myList.AddRange(A);
myList.AddRange(B);
int[] C = myList.ToArray();
//need values in this order: 10, 1, 12, 2, 8, 6, 14, 7
}
Now I wanna sort the array C this way: 10, 1, 12, 2, 8, 6, 14, 7
The smaller values should be between the larger values, for ex: 1 is between 10 and 12, 2 is between 12 and 8, 6 is between 8 and 14, so on and so forth.
How can I do this in C#?
If recursion is needed, how can I add it to the code?

What I understood from your example is that you are trying to alternate between large and small values such that the small value is always smaller than the number to the left and the right. I wrote an algorithm below to do that however it does not yield the exact same results you requested. However I believe it does meet the requirement.
The straggling 7 is considered the next smallest number in the sequence but there is no number that follows it. Based on your example it appears that is allowed.
To Invoke
int[] A = { 10, 12, 6, 14, 7 };
int[] B = { 1, 8, 2 };
var result = Sort(A, B);
Sort Method
public static int[] Sort(int[] A, int[] B)
{
var result = new int[A.Length + B.Length];
var resultIndex = 0;
Array.Sort(A);
Array.Sort(B);
//'Pointer' for lower index, higher index
var aLeft = 0;
var aRight = A.Length-1;
var bLeft = 0;
var bRight = B.Length - 1;
//When Items remain in both arrays
while (aRight >= aLeft && bRight >= bLeft)
{
//Add smallest
if (resultIndex % 2 > 0)
{
if (A[aLeft] < B[bLeft])
result[resultIndex++] = A[aLeft++];
else
result[resultIndex++] = B[bLeft++];
}
//Add largest
else
{
if (A[aRight] > B[bRight])
result[resultIndex++] = A[aRight--];
else
result[resultIndex++] = B[bRight--];
}
}
//When items only in array A
while (aRight >= aLeft)
{
//Add smallest
if (resultIndex % 2 > 0)
result[resultIndex++] = A[aLeft++];
//Add largest
else
result[resultIndex++] = A[aRight--];
}
//When items remain only in B
while (bRight >= bLeft)
{
//Add smallest
if (resultIndex % 2 > 0)
result[resultIndex++] = B[bLeft++];
//Add largest
else
result[resultIndex++] = B[bRight--];
}
return result;
}
Result
[14, 1, 12, 2, 10, 6, 8, 7]

Related

How do I remove each N item in List until List.Count more than target value?

There is a list of short. The values of it doesn't matter like:
List<short> resultTemp = new List<short>{1,2,3,4,5,6,7,8,9...};
This code should reduse the result list count by removing each Nth item from it.
Example 1:
List<short>{1,2,3,4,5,6,7,8,9,10}.Count == 10;
var targetItemsCount = 5;
result should be {1,3,5,7,9} and result.Count should be == 5
Example 2:
List<short>{1,2,3,4,5,6,7,8,9}.Count == 9;
var targetItemsCo:nt = 3;
result should be {1,4,7} and result.Count should be == 3
But it should stop to remove it, somewhere for make result count equal targetItemsCount (42 in this code, but its value else doesn't matter).
The code is:
var currentItemsCount = resultTemp.Count;
var result = new List<short>();
var targetItemsCount = 42;
var counter = 0;
var counterResettable = 0;
if (targetItemsCount < currentItemsCount)
{
var reduceIndex = (double)currentItemsCount / targetItemsCount;
foreach (var item in resultTemp)
{
if (counterResettable < reduceIndex ||
result.Count + 1 == currentItemsCount - counter)
{
result.Add(item);
counterResettable++;
}
else
{
counterResettable = 0;
}
counter++;
}
}
And the resault.Count in this example equals 41, but should be == targetItemsCount == 42;
Ho do I remove each N item in List untill List.Count more then target value with C#?
If my understanding is correct:
public static void run()
{
var inputs =
new List<Input>{
new Input{
Value = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },`
TargetCount = 5, ExpectedOutput= new List<int>{1,3,5,7,9}
},
new Input{
Value = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 },
TargetCount = 3, ExpectedOutput= new List<int>{1,4,7}
},
};
foreach (var testInput in inputs)
{
Console.WriteLine($"# Input = [{string.Join(", ", testInput.Value)}]");
var result = Reduce(testInput.Value, testInput.TargetCount);
Console.WriteLine($"# Computed Result = [{string.Join(", ", result)} ]\n");
}
}
static List<int> Reduce(List<int> input, int targetItemsCount)
{
while (input.Count() > targetItemsCount)
{
var nIndex = input.Count() / targetItemsCount;
input = input.Where((x, i) => i % nIndex == 0).ToList();
}
return input;
}
class Input
{
public List<int> ExpectedOutput;
public List<int> Value;
public int TargetCount;
}
Result :
Input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Computed Result = [1, 3, 5, 7, 9 ]
Input = [1, 2, 3, 4, 5, 6, 7, 8, 9]
Computed Result = [1, 4, 7 ]
To guarantee you get the expected number of selected items:
double increment = Convert.ToDouble(resultTemp.Count) / targetItemsCount;
List<short> result = Enumerable.Range(0, targetItemsCount).
Select(x => resultTemp[(int)(x * increment)]).
ToList();
Note that in the following case
List<short>{1,2,3,4,5,6,7,8,9}.Count == 9;
var targetItemsCount = 6;
The result will be [1, 2, 4, 5, 7, 8], i.e. rounding the index down when needed
Also, you'll need to add validation (targetItemsCount > 0, targetItemsCount < resultTemp.Count...)
Link to Fiddle
Give this a try:
var resultTemp = Enumerable.Range(1, 9).ToList();
var targetItemsCount = 3;
var roundingError = resultTemp.Count % targetItemsCount;
var reduceIndex = (resultTemp.Count - roundingError) / targetItemsCount;
List<int> result;
if (reduceIndex <= 1)
result = resultTemp.Take(targetItemsCount).ToList();
else
result = resultTemp.Where((a, index) => index % reduceIndex == 0).Take(targetItemsCount).ToList();
Tried it with your given example, also gave 42 a spin with a list of 1 to 100 it will remove every 2nd item till it reaches 42, so the last entry in the list would be 83.
As I said, give it a try and let me know if it fits your requirement.

Splitting 8 elements from one list into the first element of another C#

one a integer list and one a string list. The integer list's length will always be a multiple of 8. I would like to put the first 8 integers from my integer list into the first element of a string list, then loop and put the next 8 into the second element of the string list and so on. I have made an attempt, I currently have an error on the Add method as string doesn't have an add extension? Also I'm not sure if the way I have done it using loops is correct, any advice would be helpful.
List1 is my integer list
List2 is my string list
string x = "";
for (int i = 0; i < List1.Count/8; i++) {
for(int i2 = 0; i2 < i2+8; i2+=8)
{
x = Convert.ToString(List1[i2]);
List2[i].Add(h);
}
}
You can do that by using something like that
var list1 = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
var list2 = new List<string>();
for (int i = 0; i < list1.Count / 8; i++)
{
list2.Add(string.Concat(list1.Skip(i * 8).Take(8)));
}
// list2[0] = "12345678"
// list2[1] = "910111213141516"
A slightly more complicated approach, which only iterates once over list1 (would work with IEnumerable would be sth. like this:
var list1 = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }.AsEnumerable();
var list2 = new List<string>();
var i = 0;
var nextValue = new StringBuilder();
foreach (var integer in list1)
{
nextValue.Append(integer);
i++;
if (i != 0 && i % 8 == 0)
{
list2.Add(nextValue.ToString());
nextValue.Clear();
}
}
// could add remaining items if count of list1 is not a multiple of 8
// if (nextValue.Length > 0)
// {
// list2.Add(nextValue.ToString());
// }
For the fun of it, you can implement your own general purpose Batch extension method. Good practice to understand extension methods, enumerators, iterators, generics and c#'s local functions:
static IEnumerable<IEnumerable<T>> Batch<T>(
this IEnumerable<T> source,
int batchCount,
bool throwOnPartialBatch = false)
{
IEnumerable<T> nextBatch(IEnumerator<T> enumerator)
{
var counter = 0;
do
{
yield return enumerator.Current;
counter += 1;
} while (counter < batchCount && enumerator.MoveNext());
if (throwOnPartialBatch && counter != batchCount) //numers.Count % batchCount is not zero.
throw new InvalidOperationException("Invalid batch size.");
}
if (source == null)
throw new ArgumentNullException(nameof(source));
if (batchCount < 1)
throw new ArgumentOutOfRangeException(nameof(batchCount));
using (var e = source.GetEnumerator())
{
while (e.MoveNext())
{
yield return nextBatch(e);
}
}
}
Using it is rather trivial:
var ii = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
var ss = ii.Batch(4, true)
.Select(b => string.Join(", ", b))
And sure enough, the output is:
1, 2, 3, 4
5, 6, 7, 8
9, 10, 11, 12
while (listOfintergers.Count() > 0)
{
var first8elements = listOfintergers.ConvertAll(t=>t.ToString()).Take(8);
listOfStrings.Add(string.Concat(first8elements));
listOfintergers = listOfintergers.Skip(8).ToList();
}

How many values are in sequence from an array

I want to find how many values, in an array, are in sequence without sorting.
For Instance, if I have.
int[] arr = new int[] { 0, 1, 2, 3, 4, 5, 6, 9 } //0, 1, 2, 3, 4, 5, 6 are in sequence
int value = HighestSequence(arr);
//value prints 7
int[] arr = new int[] { 0, 4, 1, 2, 3, 4, 7, 9 } //1, 2, 3, 4 are in sequence
int value = HighestSequence(arr);
//value prints 4
int[] arr = new int[] { 0, 1, 2 } //0, 1, 2 is in sequence
int value = HighestSequence(arr);
//value prints 3
You don't specify what should happen if there is more than one subsequence in order, but I've assumed there will be only one.
Try this:
int length = 1;
int[] arr = new int[] { 0, 1, 2, 3, 4, 5, 6, 9 }; //0, 1, 2, 3, 4, 5, 6 are in sequence
//value prints 7
List<int> temp = arr.Zip(arr.Skip(1), (i1, i2) => length += (i2 - i1 == 1 ? 1 : 0)).ToList();
Length will contain the number of integers in sequence where arr[n] == arr[n+1] - 1
Cheers
EDIT:
In the case where there is more than one subsequence that is ordered such that arr[n] == arr[n+1] - 1, we'd need to decide how to handle it.
One way would be to reset the length when we find a value that doesn't meet the criteria:
arr = new int[] { 0, 1, 2, 5, 4, 5, 6, 9 }; //Possible bug ?
length = 1;
temp = arr.Zip(arr.Skip(1), (i1, i2) =>
{
if(i2 - i1 == 1)
{
length++;
}
else
{
length = 1;
}
return i1;
}).ToList();
But then this will not consider the "longest" subsequence, it will return the length of the "last" subsequence in the sequence.
The OP should specify what action he wants in such cases.
EDIT #2:
If we want to have the longest subsequence, then this could be used:
arr = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 5, 4, 5, 6, 7, 9 }; //Possible bug ?
length = 1;
int longest = length;
temp = arr.Zip(arr.Skip(1), (i1, i2) =>
{
if (i2 - i1 == 1)
{
if (++length > longest)
longest = length;
}
else
{
length = 1;
}
return i1;
}).ToList();
Caching the longest ordered subsequence length. Then use longest instead of length as the result.
EDIT #3:
Edits #1 & 2 should now contain the appropriate solution. I was obviously trying to come up with a solution to a comment from a user too quickly and I didn't realize that the current code in my VS solution was different than the code I posted here.
It is to be mentioned that the OP didn't have those additional constraints, and that I did mention right from the get go that my solution didn't address those additional constraints.
Nonetheless, it was an interesting problem to solve ;-)
Cheers
Try this out. I got the results of (7,4,3). Although Peter is correct about StackOverflow you should give your attempt and say your issue not just ask for an answer. I only provided it because it was a neat challenge.
var set1 = new [] { 0, 1, 2, 3, 4, 5, 6, 9 };
var result1 = HighestSequence(set1);
var set2 = new[] { 0, 4, 1, 2, 3, 4, 7, 9 };
var result2 = HighestSequence(set2);
var set3 = new [] { 0, 1, 2 };
var result3 = HighestSequence(set3);
public int HighestSequence(int[] values)
{
IList<int> sequenceCounts = new List<int>();
var currentSequence = 0;
for (var i = 0; i < values.Length; i++)
{
if (i == (values.Length - 1)) //End edge case
{
if (values[i] - values[i - 1] == 1)
{
currentSequence++;
sequenceCounts.Add(currentSequence);
}
}
else if ((values[i] + 1) == values[i + 1])
{
currentSequence++;
}
else
{
currentSequence++;
sequenceCounts.Add(currentSequence);
currentSequence = 0;
continue;
}
sequenceCounts.Add(currentSequence);
}
return sequenceCounts.Max();
}

Randomly pick from a list of numbers until specific limit

Let's say I have a list of predefined numbers, and a list of predefined max limits.
When a user picks a limit, I need to randomly pick a certain amount of numbers from the first list, up until their totals match (As close to, but never over) the user selected total.
What I've tried so far:
void Main()
{
List<int> num = new List<int>(){ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,17, 18, 19, 20 };
int maxNum = 17;
List<int> curNum = new List<int>();
int curTotal = 0;
foreach(int sel in num.Where(x => x < maxNum)){
curTotal += sel;
if(curTotal <= maxNum){
curNum.Add(sel);
}
}
}
There needs to be x amount of numbers picked. In this case, 5 numbers picked, +- 20 numbers to be randomly picked from, and 1 max values.
So the end list should look like this:
1, 2, 3, 4, 7 (17)
1, 2, 3, 5, 6 (17)
1, 2, 3, 4, 6 (16) <- This will be fine if there isn't a solution to the max value.
Building upon #AlexiLevenkov's answer:
class Program
{
static void Main(string[] args)
{
int limit = 17;
int listSize = 5;
List<int> a = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
a.Shuffle();
List<int> genList = new List<int>();
int stoppedCount = 0;
for (int i = 0; i < a.Count(); i++)
{
if (i < listSize)
{
genList.Add(a[i]);
stoppedCount = i;
}
else
{
break;
}
}
while (genList.Sum() > limit)
{
genList.Remove(genList.Max());
stoppedCount++;
genList.Add(a[stoppedCount]);
}
}
}
static class ThisClass
{
public static void Shuffle<T>(this IList<T> list)
{
Random rng = new Random();
int n = list.Count;
while (n > 1)
{
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
I think shuffle + "take while sum < limit" may be what you are looking for.
Something like following:
var shuffledList = num.ToList();
shuffledList.Shuffle();
var sum = 0;
var count = 0;
while (shuffledList[count] + sum < max)
{
sum += shuffledList[count++];
}
return shuffledList.Take(count);

Get indices of top x equal elements

I need to get the indices of all the largest elements who are equal to each other in a sorted list of ints.
So given this list
elements: {1 , 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 11, 11, 12, 13, 13, 13}
index: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
^ ^ ^
I will get this output
{16,17,18}
So far I've got
list.Select((x, i) => new {x, i})
To get the indices, but I can't use OrderBy() with First() or Single() because I need all the max elements' indices, not just the very top one.
Is there an elegant way to accomplish this (with LINQ or otherwise)?
Thus items are sorted, you only need to get index of first item with max value (that item will have exactly same value as last item), and then create range of indexes starting from this index to the end of list:
var items = new List<int> {1,1,2,3,4,4,5,6,7,7,8,9,10,11,11,12,13,13,13};
int startIndex = items.IndexOf(items[items.Count - 1]);
var indexes = Enumerable.Range(startIndex, items.Count - startIndex);
The easy/lazy way:
var a = new[] {1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 11, 11, 12, 13, 13, 13};
var b = new List<int>();
var max = a.Max();
for (var i = 0; i < a.Length; i++)
{
if (a[i] == max) b.Add(i);
}
I wouldn't use LINQ since it is a simple foreach over the collection.
//var data = new[] {1, 1, 13, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 11, 11, 12, 13, 13, 13};
var data = new[] {1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 11, 11, 12, 13, 13, 13};
var largest = int.MinValue;
var indices = new List<int>();
foreach (var x in data.Select((value, idx) => new {value, idx}))
{
if (x.value > largest)
{
indices.Clear();
largest = x.value;
}
// if unsorted
//if (x.value == largest) indices.Add(x.idx);
// if sorted you don't need to check against largest
indices.Add(x.idx);
}
Console.WriteLine("largest = {0}; indices = {1}", largest, string.Join(", ", indices));
Though if you must use LINQ, you can use this option instead of the foreach:
data.Select((value, idx) => new {value, idx})
.Aggregate(indices, (idxs, n) =>
{
if (n.value > largest)
{
idxs.Clear();
largest = n.value;
}
//unsorted
if (n.value == largest) idxs.Add(n.idx);
//sorted
//idxs.Add(n.idx);
return idxs;
});
This will get you a result of all the elements that have duplicates with their indices:
var result = elements.Select((value, index) => new { value, index })
.Where(g => elements.FindAll(v => v == g.value).Count > 1)
.GroupBy((a) => a.value).OrderByDescending((g) => g.Key).Take(3);
//I placed Take(3) as example since you said you need to find
//elements who are equal to each other,so only those that are
// not distinct(have duplicates) get into the collection.
//this will loop through the results and display the value(the item
//on the list) and its respective index.
foreach (var item in result.SelectMany(g => g))
{
string outcome = item.value + " - " + item.index;
Console.WriteLine(outcome);
}

Categories

Resources