I'm trying to reorganize an array based on the first occurrence of a value (thus simulating similar functionality to a circular array.)
For example, in the following array I wish the first occurrence of the value 6 to become the new first element, and prior elements to become the latter:
So:
int[] myArray = {2, 3, 6, 1, 7, 6};
Becomes:
myArray = {6, 1, 7, 6, 2, 3};
What is the "best" way to achieve this?
int[] myArray = { 2, 3, 6, 1, 7, 6 };
myArray = myArray
.SkipWhile(i => i != 6)
.Concat(myArray.TakeWhile(i => i != 6))
.ToArray();
Should do the trick!
You will need a using System.Linq;
Thorsten's solution creates a new array; here's an in place version which only creates a temporary array as large as the amount your rotation size:
public static void RotateLeft<T>(T[] array, int places)
{
T[] temp = new T[places];
Array.Copy(array, 0, temp, 0, places);
Array.Copy(array, places, array, 0, array.Length - places);
Array.Copy(temp, 0, array, array.Length - places, places);
}
I'm sure it could be done with just a single temporary buffer item, but it would be more complicated :)
As an efficiency measure, here's a "rotate left one place" shortcut:
public static void RotateLeft<T>(T[] array)
{
T temp = array[0];
Array.Copy(array, 0, array, 1, array.Length - 1);
array[array.Length-1] = temp;
}
You could do the following:
Create new array of same size as original
Determine your "Start index"
Use Array.Copy() to copy everything from start index to end of source array to destination array
Use Array.Copy() to copy everything from 0 to start index of source array to the end of the destination array
That way you get a copy of your source array that looks as you expected.
You'll have to play with various overloads of Array.Copy(), however, because I don't know the exact parameter values right now.
To begin with, do a linear search to find the first occurrence of the value that you want to make the first element:
// value contains the value to find.
int skip;
for (int i = 0; i < array.Length; i++)
{
if (array[i] == value)
{
skip = i;
break;
}
}
// skip contains the index of the element to put at the front.
// Equivalently, it is the number of items to skip.
// (I chose this name for it because it makes the subtractions
// in the Array.Copy implementation more intuitive.)
Do you want to change the actual array? Then do what Thorsten Dittmar suggests:
int[] array = new int[] { 2, 3, 6, 1, 7, 6 };
int[] result = new int[array.Length];
int skip = 2; // So that array[skip] will be result[0] at the end
Array.Copy(array, skip, result, 0, array.Length - skip);
Array.Copy(array, 0, result, array.Length - skip, skip);
Do you want to just view the array in the new order, without doing anything else? Then index it like so:
array[(i + skip) % array.Length] // Instead of array[i]
Edit: Just for laughs, an implementation of Jon Skeet's suggestion to implement the copy while using only a single buffer value (sourceValue):
// GCD gives the greatest common divisor
int gcd = GCD(array.Length, skip);
// period is the length of the permutation cycles in our rotation.
int period = array.Length / gcd;
int max = array.Length / period;
for (int i = 0; i < max; i++)
{
int sourceIndex = i;
int sourceValue = array[sourceIndex];
for (int n = 1; n <= period; n++)
{
int destinationIndex = (sourceIndex + array.Length - skip) % array.Length;
int temp = array[destinationIndex];
array[destinationIndex] = sourceValue;
sourceValue = temp;
sourceIndex = destinationIndex;
}
}
As an alternative to creating a new array, you can wrap it with a class:
class CircularList<T> : IList<T>
{
static IEnumerable<T> ToEnumerator(CircularList<T> list)
{
for (int i = 0; i < list.Count; i++)
{
yield return list[i];
}
}
IList<T> arr;
public int Shift { get; private set; }
public CircularList(IList<T> arr, int shift)
{
this.arr = arr;
this.Shift = shift;
}
int shiftIndex(int baseIndex)
{
return (baseIndex + Shift) % arr.Count;
}
#region IList<T> Members
public int IndexOf(T item) { throw new NotImplementedException(); }
public void Insert(int index, T item) { throw new NotImplementedException(); }
public void RemoveAt(int index) { throw new NotImplementedException(); }
public T this[int index]
{
get { return arr[shiftIndex(index)]; }
set { arr[shiftIndex(index)] = value; }
}
#endregion
#region ICollection<T> Members
public void Add(T item) { throw new NotImplementedException(); }
public void Clear() { throw new NotImplementedException(); }
public bool Contains(T item) { throw new NotImplementedException(); }
public void CopyTo(T[] array, int arrayIndex) { throw new NotImplementedException(); }
public int Count { get { return arr.Count; } }
public bool IsReadOnly { get { throw new NotImplementedException(); } }
public bool Remove(T item) { throw new NotImplementedException(); }
#endregion
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
return ToEnumerator(this).GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return ToEnumerator(this).GetEnumerator();
}
#endregion
}
This program:
class Program
{
static void Main(string[] args)
{
int[] myArray = { 2, 3, 6, 1, 7, 6 };
CircularList<int> circularList =
new CircularList<int>(myArray, Array.IndexOf<int>(myArray, 6));
foreach (int i in circularList)
{
Console.WriteLine(i);
}
}
}
Prints the following:
6
1
7
6
2
3
var ar = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
ar = ar.SkipWhile(a => a != 6).ToArray<int>();
C# answer:
input : { 1, 2, 3, 5, 6, 7, 8 };
Output : { 8, 7 1, 2, 3, 5, 6};
{
static void Main(string[] args)
{
int[] array = { 1, 2, 3, 5, 6, 7, 8 };
int index = 2;
int[] tempArray = new int[array.Length];
array.CopyTo(tempArray, 0);
for (int i = 0; i < array.Length - index; i++)
{
array[index + i] = tempArray[i];
}
for (int i = 0; i < index; i++)
{
array[i] = tempArray[array.Length -1 - i];
}
}
}
New approach that will only work with .NET 4.5 (from 2012) or later:
const int value = 6;
int[] myArray = { 2, 3, 6, 1, 7, 6, };
var index = Array.IndexOf(myArray, value);
if (index == -1)
throw new InvalidOperationException();
var rotatedArray = (new ArraySegment<int>(myArray, index, myArray.Length - index))
.Concat(new ArraySegment<int>(myArray, 0, index))
.ToArray();
In earlier .NET versions, an ArraySegment<> value could not be used as an IEnumerable<> like that.
Not clear to me if it was a requirement that the original array instance be mutated, but if you need that, simply append:
rotatedArray.CopyTo(myArray, 0);
to my code.
Related
I have this method Shuffle that supposes to return a set of random numbers which was displayed in the above method but the numbers need to be displayed in a mixed format.
The first method works well since the number are being displayed correctly in the set of range but this method Shuffle is not returning them in a mixed format.
Example:
The first method returned: 1, 2, 3, 4, 5
This method needs to return 2, 1, 4, 5, 3
public int[] Shuffle(int[] Sequence)
{
int[] Array = new int[Sequence.Length];
for(int s=0; s < Array.Length-1; s++){
int GenObj = GenerateAnotherNum (0, Array.Length + 1);
Array[s] = Sequence[GenObj];
Sequence[GenObj] = Array[s];
}
return Sequence;
}
You have several problems here: all zeroes array, range and swap procedure
Algorithm:
https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
Code:
// probably "static" should be added (depends on GenerateAnotherNum routine)
public int[] Shuffle(int[] Sequence)
{
// public method's arguments validation
if (null == Sequence)
throw new ArgumentNullException(nameof(Sequence));
// No need in Array if you want to modify Sequence
for(int s = 0; s < Sequence.Length - 1; s++)
{
int GenObj = GenerateAnotherNum(s, Sequence.Length); // pleace, note the range
// swap procedure: note, var h to store initial Sequence[s] value
var h = Sequence[s];
Sequence[s] = Sequence[GenObj];
Sequence[GenObj] = h;
}
return Sequence;
}
Demo:
// Random(0) - we want to reproduce the results in the demo
private static Random random = new Random(0);
// Let unknown GenerateAnotherNum be a random
private static int GenerateAnotherNum(int from, int to) => random.Next(from, to);
...
int[] array = new int[] { 1, 2, 3, 4, 5 };
string result = string.Join(", ", Shuffle(array));
Console.Write(result);
Outcome:
4, 5, 2, 3, 1
public static class Shuffler<T>
{
private static Random r = new Random();
public static T[] Shuffle(T[] items)
{
for(int i = 0; i < items.Length - 1; i++)
{
int pos = r.Next(i, items.Length);
T temp = items[i];
items[i] = items[pos];
items[pos] = temp;
}
return items;
}
public static IList<T> Shuffle(IList<T> items)
{
for(int i = 0; i < items.Count - 1; i++)
{
int pos = r.Next(i, items.Count);
T temp = items[i];
items[i] = items[pos];
items[pos] = temp;
}
return items;
}
}
I have an array of integers where each value will have distinct meanings.The first value means the length of permutation, the second value represent the length of initial prefix and rest of integers are single integer that make up prefix of all permutations.
For e.g. if the array has elements {5,2,1,4}
where 5 is the number of elements in the permutation array.
and 2 is the length of the integer that will makeup the first 2 elements prefix in the array permutation. 1,4 are the prefix integers i.e. length 2 in 5 element permutation combination so missing elements are 2,3,5 where 1&4 being common prefix across all permutations as below
[14235][14253][14325][14352][14523][14532] where input array is {5,2,1,4}
How to achieve this?
I have below code to get the permutation of one missing elements 2,3 & 5 but I am not getting how to program the entire the solution
static void Main(string[] args)
{
int output;
int ip1;
ip1 = Convert.ToInt32(Console.ReadLine());
int ip2_size = 0;
ip2_size = Convert.ToInt32(Console.ReadLine());
int[] ip2 = new int[ip2_size];
int ip2_item;
for (int ip2_i = 0; ip2_i < ip2_size; ip2_i++)
{
ip2_item = Convert.ToInt32(Console.ReadLine());
ip2[ip2_i] = ip2_item;
}
output = correctResult(ip1, ip2);
Console.WriteLine(output);
}
static int correctResult(int n, int[] arr)
{
int permLength = 0;
int prefLength = 0;
int result = 0;
permLength = n;
prefLength = arr.Length;
int[] permArray = new int[permLength];
int len = 0;
var missingNum = Enumerable.Range(1,
permLength).Except(arr).ToArray<int>();
if (permLength < (missingNum.Length + len))
{
result = -1;
}
else
{
for (int i = 0; i < missingNum.Length; i++)
{
permArray[prefLength + i] = missingNum[i];
}
result = permute(missingNum, 0, missingNum.Length - 1);
}
return result;
}
static int permute(int[] arry, int i, int n)
{
int j;
if (i == n)
{
int s1, s2;
s1 = s2 = 0;
for (int a = 0; a < n - 1; a++)
{
for (int b = a + 1; b < n; b++)
{
if (arry[a] > arry[b])
{
s1++;
}
}
s2 = s2 + Math.Max(0, a + 1 - arry[a]);
}
int count = 0;
if (s1 == s2)
count++;
return count;
}
else
{
int count = 0;
for (j = i; j <= n; j++)
{
swap(ref arry[i], ref arry[j]);
count += permute(arry, i + 1, n);
swap(ref arry[i], ref arry[j]);
}
return count;
}
}
static void swap(ref int a, ref int b)
{
int tmp;
tmp = a;
a = b;
b = tmp;
}
Try solving this with immutable types, its easier to reason about them. If, after solving the problem, you have a performance goal you haven't met then you can start trying to optimize the code.
Consider the following approach with an immutable stack that keeps track of the current permutation:
static IEnumerable<IEnumerable<int>> GetPermutations(IList<int> input)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
if (input.Count < 2)
throw new ArgumentException("Input does not have a valid format.");
var setSize = input[0];
var prefixSize = input[1];
if (prefixSize != input.Count - 2)
throw new ArgumentException("Input does not have a valid format.");
if (input.Skip(2).Any(i => i > setSize)) //we are assuming, per example, that valid range starts at 1.
throw new ArgumentException("Input does not have a valid format.");
//Ok, we've got a valid input, interesting stuff starts here.
var prefix = input.Skip(2).ToArray();
var initialSet = Enumerable.Range(1, setSize)
.Except(prefix)
.ToArray();
foreach (var p in getPermutations(ImmutableStack<int>.Empty, initialSet))
{
yield return prefix.Concat(p);
}
IEnumerable<IEnumerable<int>> getPermutations(ImmutableStack<int> permutation, IEnumerable<int> set)
{
if (permutation.Count == setSize - prefixSize)
{
yield return permutation;
}
else
{
foreach (var i in set)
{
foreach (var p in getPermutations(permutation.Push(i), set.Except(new[] { i })))
{
yield return p;
}
}
}
}
}
And that is it, solving your problem was about 10-12 lines of real code (not considering input validation). Note that I am using some c#7 features here, but its easily translatable to previous versions of the language. Also I'd like to underline the argument validation we are doing upfront; make sure you have a valid input before trying out anything.
For ImmutableStack<T> you can use the one in System.Collections.Immutable (you have to download the NuGet package) or implement your own, its simple:
private class ImmutableStack<T>: IEnumerable<T>
{
public static readonly ImmutableStack<T> Empty = new ImmutableStack<T>();
private readonly T head;
private readonly ImmutableStack<T> tail;
private ImmutableStack() { }
private ImmutableStack(T head, ImmutableStack<T> tail)
{
Debug.Assert(tail != null);
this.head = head;
this.tail = tail;
Count = tail.Count + 1;
}
public int Count { get; }
public T Peek() =>
this != Empty ? head : throw new InvalidOperationException("Empty stack.");
public ImmutableStack<T> Pop() =>
this != Empty ? tail : throw new InvalidOperationException("Empty stack.");
public ImmutableStack<T> Push(T item) => new ImmutableStack<T>(item, this);
public IEnumerator<T> GetEnumerator()
{
var current = this;
while (current != Empty)
{
yield return current.head;
current = current.tail;
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
If you use the collections in System.Collections.Immutable, then you'll probably want to use some kind of immutable set for initalSet and set.
You can rewrite your permute method (based on this answer):
private static IEnumerable<IEnumerable<T>> Permute<T>(List<T> prefix, List<T> suffix)
{
for (var i = 0; i < suffix.Count; ++i)
{
var newPrefix = new List<T>(prefix) {suffix[i]};
var newSuffix = new List<T>(suffix.Take(i).Concat(suffix.Skip(i + 1)));
if (newSuffix.Count == 0)
{
yield return newPrefix;
continue;
}
foreach (var permutation in Permute(newPrefix, newSuffix))
yield return permutation;
}
}
And use it like this:
public static void PrintAllPermutations()
{
var input = new[] {5, 2, 1, 4};
var prefix = input.Skip(2).Take(input[1]).ToList();
var suffx = Enumerable.Range(1, input[0]).Except(prefix).ToList();
foreach (var permutation in Permute(prefix, suffx))
Console.WriteLine(string.Join(", ", permutation));
}
Reult would be:
1, 4, 2, 3, 5
1, 4, 2, 5, 3
1, 4, 3, 2, 5
1, 4, 3, 5, 2
1, 4, 5, 2, 3
1, 4, 5, 3, 2
I have an int array in one dimension:
var intArray=new[] { 1, 2, 3, 4, 5, 6 };
and I want to convert it to two dimensions, such as:
var intArray2D=new[,] { {1, 2}, {3, 4}, {5, 6} };
How do I achieve this with C#?
with a loop perhaps:
for (int i = 0; i < oldArr.Length; i=i+2)
{
newArr[i/2, 0] = oldArr[i];
newArr[i/2, 1] = oldArr[i + 1];
}
Untested, but should get you pointed in the right direction...
If the one dimensional array contains the primitive data in row major order, and the total capacity of the 2 dimensional array equals the length of the one dimensional array, you can use this.
int[] source = new int[6];
int[,] target = new int[3, 2];
Buffer.BlockCopy(source, 0, target, 0, source.Length * sizeof(int));
Note that unlike Array.Copy and other array/list methods, Buffer.BlockCopy operates on a number of bytes of data, even if each element of the array is larger than 1 byte. It also only operates on arrays of primitive data types.
Additional references:
Multi-dimensional arrays are stored in row-major order (ECMA-335 Partition I, §8.9.1)
Buffer.BlockCopy
Edit: Here is a complete unit test.
[TestMethod]
public void SOTest16203210()
{
int[] source = new int[6] { 1, 2, 3, 4, 5, 6 };
int[,] destination = new int[3, 2];
Buffer.BlockCopy(source, 0, destination, 0, source.Length * sizeof(int));
Assert.AreEqual(destination[0, 0], 1);
Assert.AreEqual(destination[0, 1], 2);
Assert.AreEqual(destination[1, 0], 3);
Assert.AreEqual(destination[1, 1], 4);
Assert.AreEqual(destination[2, 0], 5);
Assert.AreEqual(destination[2, 1], 6);
}
I believe you want to split an integer array into an array of two integers each:
int[] list = new int[] { 1, 2, 3, 4, 5, 6};
int[][] newlist = new int[list.Length / 2][];
for (int i = 0, n = 0; i < list.Length; i += 2, n++)
{
newlist[n] = new[] { list[i], list[i + 1] };
}
To assign it to Points in particular you could try:
List<Point> plist = new List<Point>();
for (int i = 0; i < list.Length; i += 2)
{
plist.Add(new Point(list[i], list[i + 1]));
}
you may use this code. in here you can send any length you like. you can "deivde" the arry[] to arry[,] for any lenth.2 or 3 or what ever you like! as long as size % a.length ==0 !!!!
code
static int[,] convert(int[] a, int size)
{
int[,] value = new int[a.Length / size, size];
int counter = 0;
//
for (int b = 0; b < value.GetLength(0); b++)
for (int c = 0; c < value.GetLength(1); c++)
{
value[b, c] = a[counter];
counter++;
}
return value;
}
If the product of the dimensions are the same, the fastest way would probably be to pin the matrix using a fixed statement, then to use the Marshalling class to copy the continuous block from the array to an IntPtr created from the void* you got from the fixed.
You would have to wrap this in an unsafe statement and enable unsafe in the assembly's build config.
I have converted this from vb to c#
int Size = OldArray.Length;
int[,] NewPoints = null;
if (Size % 2 != 0) {
//Error - Array has odd number of elements!
} else {
for (i = 0; i <= Size - 1; i += 2) {
Array.Resize(ref AllPoints, (i / 2) + 1, 2);
NewPoints[i / 2, 0] = OldArray(i);
NewPoints[i / 2, 1] = OldArray(i + 1);
}
}
You could try this:
int [] a = {1,2,3,4,5,6};
int [,] b = new int[a.Length/2,2];
for(int i = 0;i<a.Length;i++)
{
b[i/2,i%2] = a[i];
}
Note that i/2 is an integer division, hence both 4/2 and 5/2 will give 2 which is a correct index in 2Darray for the tuple 5 and 6 from the original array. The second index is determined using reminder when divided by 2, it will give 0 if the index is even number and 1 if the index of the item from the original array is odd number.
I would consider this for any dimension of array:
public class TestClass {
public static void TestMethod2D() {
var intLinear=new[] { 1, 2, 3, 4, 5, 6 };
var indexer2D=new ArrayIndexer<int>(3, 2);
for(var i=intLinear.Length; i-->0; indexer2D[i]=intLinear[i])
;
var int2D=(int[,])indexer2D.ToArray();
}
public static void TestMethod4D() {
var intLinear=new[] { 1, 2, 3, 4, 5, 6 };
var indexer4D=new ArrayIndexer<int>(2, 2, 2, 2);
for(var i=intLinear.Length; i-->0; indexer4D[i]=intLinear[i])
;
var int4D=(int[, , ,])indexer4D.ToArray();
}
}
public partial class ArrayIndexer<T> {
public Array ToArray() {
return m_Array;
}
public ArrayIndexer(params int[] lengths) {
m_Array=Array.CreateInstance(typeof(T), lengths);
}
public T this[params int[] indices] {
set {
m_Array.SetValue(value, indices.Transform(m_Array));
}
get {
return (T)m_Array.GetValue(indices.Transform(m_Array));
}
}
Array m_Array;
}
public static partial class ArrayExtensions {
public static int[] Transform(
this int[] indices, Array array, bool isRowMajor=true) {
if(indices.Length>array.Rank)
return indices;
else {
var list=indices.ToList();
if(isRowMajor)
list.Reverse();
for(int r, q=0, i=0, count=array.Rank; count-->0; ++i) {
var index=isRowMajor?count-i:i;
if(indices.Length>i) {
q=Math.DivRem(indices[i]+q, array.GetLength(index), out r);
list[i]=r;
}
else {
if(index<0) {
list.Add(q);
q=0;
}
else {
q=Math.DivRem(q, array.GetLength(index), out r);
list.Add(r);
}
}
}
if(isRowMajor)
list.Reverse();
return list.ToArray();
}
}
}
ArrayExtensions.Transform is an indices transformer, it performs the linear transformation with the geometry of a given array. isRowMajor controls the layout, such as you would regard an int[,] in x, y or in y, x order.
I need to get an element from an IEnumerable and then return itself and a range of elements on either side.
So, something like this:
var enumerable = new[] {54, 107, 24, 223, 134, 65, 36, 7342, 812, 96, 106};
var rangeSize = 2;
var range = enumerable.MySelectRange(x => x == 134, rangeSize);
would return something like { 24, 223, 134, 65, 36 }.
(This project uses .Net 3.5)
EDIT
Ok, people seem to be getting hung up on the array of ints.
I've changed the example to hopefully make it more clear what I'm after.
Bear in mind that this isn't necessarily for an IEnumerable<int>, but will actually be an IEnumerable<TSomething>.
This extension method finds the first element in the sequence satisfying a given predicate, and then returns that element along with a certain number of its neighbouring elements. It handles the end cases.
public static IEnumerable<T> FirstAndNeighbours<T>(
this IEnumerable<T> source,
Func<T,bool> predicate,
int numOfNeighboursEitherSide)
{
using (var enumerator = source.GetEnumerator())
{
var precedingNeighbours = new Queue<T>(numOfNeighboursEitherSide);
while(enumerator.MoveNext())
{
var current = enumerator.Current;
if (predicate(current))
{
//We have found the first matching element. First, we must return
//the preceding neighbours.
foreach (var precedingNeighbour in precedingNeighbours)
yield return precedingNeighbour;
//Next, return the matching element.
yield return current;
//Finally, return the succeeding neighbours.
for (int i = 0; i < numOfNeighboursEitherSide; ++i)
{
if (!enumerator.MoveNext())
yield break;
yield return enumerator.Current;
}
yield break;
}
//No match yet, keep track of this preceding neighbour.
if (precedingNeighbours.Count >= numOfNeighboursEitherSide)
precedingNeighbours.Dequeue();
precedingNeighbours.Enqueue(current);
}
}
}
Assuming you can obtain the index of the middle element:
var enumerable = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int range = 2;
int index = 10;
enumerable.Skip(index-range).Take(range)
.Union(enumerable.Skip(index).Take(1))
.Union(
enumerable.Skip(index+1).Take(range)
).Dump();
(the Dump() call is for LinqPad)
EDIT:
Thanks to Gabe's comment, got rid of the two extra Skip()/Take():
enumerable.Skip((index < range) ? 0 : index-range)
.Take(((index < range) ? index : range) + range + 1)
.Dump();
EDIT: Updated answer due to question update **
an extension method should do it, now supports any type T
public static IEnumerable<T> Range<T>(this IEnumerable<T> enumerable, Func<T,bool> selector, int size)
{
Queue<T> queue = new Queue<T>();
bool found = false;
int count = 0;
foreach(T item in enumerable)
{
if(found)
{
if(count++ < size)
{
yield return item;
}
else
{
yield break;
}
}
else
{
if(queue.Count>size)
queue.Dequeue();
if(selector(item))
{
found = true;
foreach(var stackItem in queue)
yield return stackItem;
yield return item;
}
else
{
queue.Enqueue(item);
}
}
}
usage is close to what you required
var enumerable = new[] {54, 107, 24, 223, 134, 65, 36, 7342, 812, 96, 106};
Console.WriteLine(String.Join(",",enumerable.ToArray()));
var rangeSize = 2;
var range = enumerable.Range((x) => x == 134, rangeSize);
Console.WriteLine(String.Join(",",range.ToArray()));
Live example: http://rextester.com/rundotnet?code=ACKDD76841
The following gives correct answers for non-linear sequences and is efficient, e.g:
const int PivotValue = 5;
const int RangeSize = 2;
int[] enumerable = new[] { 0, 1, 2, 3, 4, 5, 600, 700, 800, 900, 1000 };
IEnumerable<int> range = enumerable.PivotRange(PivotValue, RangeSize);}
//3, 4, 5, 600, 700.
Code - Generic Version
public static IEnumerable<T> PivotRange<T>(
this IEnumerable<T> source, T pivot, int size) where T : IComparable<T>
{
T[] left = new T[size];
int lCount = 0, rCount = 0;
IEnumerator<T> enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
T item = enumerator.Current;
if (item.CompareTo(pivot) == 0)
{
int start = lCount > size ? lCount % size : 0;
int end = Math.Min(size, lCount);
for (int i = start; i < start + end; i++)
yield return left[i % size];
yield return pivot;
while (enumerator.MoveNext() && rCount++ < size)
yield return enumerator.Current;
break;
}
if (size <= 0) continue;
left[lCount++ % size] = item;
}
}
Update - Unit Tests
[Test]
public void Linear()
{
const int PivotValue = 5;
const int RangeSize = 2;
int[] enumerable = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int[] range = enumerable.PivotRange(PivotValue, RangeSize).ToArray();
CollectionAssert.AreEqual(new[] { 3, 4, 5, 6, 7 }, range);
}
[Test]
public void NonLinear()
{
const int PivotValue = 5;
const int RangeSize = 2;
int[] enumerable = new[] { 0, 1, 2, 3, 4, 5, 600, 700, 800, 900, 1000 };
int[] range = enumerable.PivotRange(PivotValue, RangeSize).ToArray();
CollectionAssert.AreEqual(new[] { 3, 4, 5, 600, 700 }, range);
}
[Test]
public void NoLeft()
{
const int PivotValue = 5;
const int RangeSize = 2;
int[] enumerable = new[] { 5, 600, 700, 800, 900, 1000 };
int[] range = enumerable.PivotRange(PivotValue, RangeSize).ToArray();
CollectionAssert.AreEqual(new[] { 5, 600, 700 }, range);
}
[Test]
public void NoRight()
{
const int PivotValue = 5;
const int RangeSize = 2;
int[] enumerable = new[] { 0, 1, 2, 3, 4, 5 };
int[] range = enumerable.PivotRange(PivotValue, RangeSize).ToArray();
CollectionAssert.AreEqual(new[] { 3, 4, 5 }, range);
}
[Test]
public void ZeroRange()
{
const int PivotValue = 5;
const int RangeSize = 0;
int[] enumerable = new[] { 0, 1, 2, 3, 4, 5 };
int[] range = enumerable.PivotRange(PivotValue, RangeSize).ToArray();
CollectionAssert.AreEqual(new[] { 5 }, range);
}
[Test]
public void LeftShorterThanRange()
{
const int PivotValue = 5;
const int RangeSize = 2;
int[] enumerable = new[] { 4, 5, 6, 7, 8 };
int[] range = enumerable.PivotRange(PivotValue, RangeSize).ToArray();
CollectionAssert.AreEqual(new[] { 4, 5, 6, 7 }, range);
}
[Test]
public void RightShorterThanRange()
{
const int PivotValue = 5;
const int RangeSize = 2;
int[] enumerable = new[] { 2, 3, 4, 5, 6, };
int[] range = enumerable.PivotRange(PivotValue, RangeSize).ToArray();
CollectionAssert.AreEqual(new[] { 3, 4, 5, 6 }, range);
}
You can do something like this.
var enumerable = new[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
var rangeSize = 2;
var index = enumerable.FirstOrDefault(x=> x == 2);
var range = enumerable.Skip(index + 1).Take(5);
As far the elements are unique, below function will work for you.
public static IEnumerable<T> MySelectRange<T>(this IEnumerable<T> me, Func<T, bool> pred, int range)
{
var first = me.TakeWhile(i => !pred(i)).TakeLast(range);
var second = me.SkipWhile(i => !pred(i)).Take(range + 1);
return first.Concat(second);
}
NOTE: The TakeLast seems to be from Rx library
Could be as simple as this:
public IEnumerable<T> GetRange<T>(IEnumerable<T> enumerable, int rangeSize, T value)
{
for (int i = 0; i < enumerable.Count(); ++i)
{
if (enumerable.ElementAt(i).Equals(value))
{
for (int j = Math.Max(0, i - rangeSize); j < Math.Min(i + rangeSize + 1, enumerable.Count()); ++j)
{
yield return enumerable.ElementAt(j);
}
}
}
}
}
This is a queue-based version, only I implement my own queue (unlike the others that use Queue). The advantage of implementing my own queue is that it is just slightly more efficient.
public static IEnumerable<T> MySelectRange<T>(this IEnumerable<T> source,
Func<T, bool> selector,
int rangeSize)
{
var firstN = new T[rangeSize];
int pos = 0;
bool found = false;
foreach (T item in source)
{
if (found)
if (pos++ <= rangeSize)
yield return item;
else
break;
if (selector(item))
{
found = true;
for (int i = Math.Max(0, pos - rangeSize); i < pos; i++)
yield return firstN[i % rangeSize];
yield return item;
pos = 0;
}
else if (rangeSize > 0)
firstN[pos++ % rangeSize] = item;
}
}
I have an array of ints
int[] RowOfints = 1,2,3,4,5,6,7,8,9;
if i enter for example value 4 i want to remove 1,2,3 from array and return what's left.
How to do that?
If you don't want to use LINQ:
int[] newRowOfInts = new int[RowOfInts.Length - index];
Array.Copy(RowOfInts, index, newRowOfInts, 0, newRowOfInts.Length);
Using Skip extension in LINQ.
int[] newArray = RowOfInts.Skip(value).ToArray();
I'm interpreting your question that you want to find the index for the value 4 and then take everything starting from that index position.
var result = RowOfInts.SkipWhile(item => item != 4); // optionally, .ToArray()
result will be an IEnumerable<int> consisting of 4 .. 9. If you want a concrete array, you can use the optional ToArray() extension method as well. If no elements in the array match the given criteria, you will get a zero-length sequence.
OK, now that I understand the question better, I will post my version of the actual requirements (again perversely emphasising effeciency over readability):
private static int[] RemoveBeforeValue(int[] source, int value)
{
if (source == null)
return null;
int valueIndex = 0;
while (valueIndex < source.Length && source[valueIndex] != value)
valueIndex++;
if (valueIndex == 0)
return source;
int[] result = new int[source.Length - valueIndex];
Array.Copy(source, valueIndex, result, 0, result.Length);
return result;
}
OLD ANSWER
If you want to do it the hard (but efficient!) way, then you can do this (assuming you want to remove values less than the supplied value):
private static int[] RemoveValuesLessThan(int[] source, int newMinimum)
{
if (source == null)
return null;
int lessThanCount = 0;
for (int index = 0; index < source.Length; index++)
if (source[index] < newMinimum)
lessThanCount++;
if (lessThanCount == 0)
return source;
int[] result = new int[source.Length - lessThanCount];
int targetIndex = 0;
for (int index = 0; index < source.Length; index++)
if (source[index] >= newMinimum)
result[targetIndex++] = source[index];
return result;
}
For a sequential array of ints
public static void RemoveIntsBefore(int i)
{
int[] RowOfints = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (int k = 0; k < RowOfints.Length; k++)
{
if (RowOfints.ElementAt(k) < i)
{
RowOfints[k] = i;
}
}
RowOfints = RowOfints.Distinct().ToArray();
//this part is to write it on console
//foreach (var item in RowOfints)
//{
// Console.WriteLine(item);
//}
//Console.ReadLine();
}
with this one your array does not have to be sequential
public static void RemoveIntsBefore(int i)
{
int[] RowOfints = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 1,2 };
Console.WriteLine("OUTPUT");
foreach (var item in Enumerable.Range(i-1, RowOfints.Length + 1 - i).ToArray())
{
Console.WriteLine(RowOfints[item]);
}
Console.ReadLine();
}
using System.Linq;
....
int[] RowOfints = {1,2,3,4,5,6,7,8,9};
int[] Answer = RowOfints.Where(x => x != 1 && x != 2 && x != 3).ToArray()