3

My problem is that I want to have a specific element in the array, copy it to another variable, shift the entire array right only up unto that element, and then put the element at the front. In a nice drawing, It'd look like this.

[0, 1, 2, 3, 4, 5]
          ^

[0, 1, 2, null, 4, 5]
          ^ (3)

[null, 0, 1, 2, 4, 5]
             ^ (3)

[null, 0, 1, 2, 4, 5]
 ^ (3)

[3, 0, 1, 2, 4, 5]
 ^

I've already tried to use a for loop to bring the elements to the front and then insert the 3, but I fear that my way of doing it isn't the most efficient or fastest way.

Here's what I've tried.

        int elementAt = 3;
        int[] array = { 0, 1, 2, 3, 4, 5 };
        int mem = array[elementAt];
        for (int i = elementAt; i > 0; i--)
            array[i] = array[i - 1];
        array[0] = mem;

I'm suspecting something like Array.Copy could do it faster...?

EDIT: Every single answer down below has their own uses in specific scenarios. There is no definitive answer for this question, let these results let you choose which method to use.

iterations, index, arraysize
HIGH, HIGH, HIGH
Speed for ShiftRightAt: 6616, ticks: 28007912
Speed for shiftlist: 3556, ticks: 15054635
Speed for arrayCopy: 1742, ticks: 7376152
Speed for MoveValueToFront: 67, ticks: 285901
LOW, LOW, HIGH
Speed for ShiftRightAt: 0, ticks: 28
Speed for shiftlist: 42, ticks: 180476
Speed for arrayCopy: 33, ticks: 142717
Speed for MoveValueToFront: 0, ticks: 67
HIGH, LOW, HIGH
Speed for ShiftRightAt: 0, ticks: 1399
Speed for shiftlist: 3624, ticks: 15341777
Speed for arrayCopy: 3177, ticks: 13449012
Speed for MoveValueToFront: 0, ticks: 926
LOW, HIGH, HIGH
Speed for ShiftRightAt: 73, ticks: 311428
Speed for shiftlist: 41, ticks: 174652
Speed for arrayCopy: 18, ticks: 79768
Speed for MoveValueToFront: 65, ticks: 277266
HIGH, HIGH, LOW
Speed for ShiftRightAt: 0, ticks: 1379
Speed for shiftlist: 0, ticks: 3902
Speed for arrayCopy: 0, ticks: 728
Speed for MoveValueToFront: 0, ticks: 914
LOW, LOW, LOW
Speed for ShiftRightAt: 0, ticks: 3
Speed for shiftlist: 0, ticks: 32
Speed for arrayCopy: 0, ticks: 11
Speed for MoveValueToFront: 0, ticks: 12
HIGH, LOW, LOW
Speed for ShiftRightAt: 0, ticks: 135
Speed for shiftlist: 0, ticks: 3850
Speed for arrayCopy: 0, ticks: 998
Speed for MoveValueToFront: 0, ticks: 840
LOW, HIGH, LOW
Speed for ShiftRightAt: 0, ticks: 15
Speed for shiftlist: 0, ticks: 16
Speed for arrayCopy: 0, ticks: 9
Speed for MoveValueToFront: 0, ticks: 39

Method of testing: https://pastebin.com/HKkixHGR

SirJosh3917
  • 309
  • 5
  • 13
  • 1
    Have you tried anything yet? – Gilad Green Jun 27 '17 at 15:02
  • What code you have written for this? What issue you are facing with that code? – Chetan Jun 27 '17 at 15:03
  • I've tried using a for loop to take the last element and put it up front, and then insert that variable, but I fear that it's not the most efficient nor fastest way. – SirJosh3917 Jun 27 '17 at 15:03
  • Please share what you have tried. Otherwise it looks like a "do my code for me" question – Gilad Green Jun 27 '17 at 15:04
  • Turn your `array` into a `list`, save your element to a variable, remove the element from the list, insert it at index 0. – Arthur Rey Jun 27 '17 at 15:06
  • why don't you use a List instead? with List you can do smth like this `list.Insert(list[index],0); list.RemoveAt(index+1);` – yolo sora Jun 27 '17 at 15:06
  • Added what I've tried in the main topic. I don't want to use a list because I believes arrays are faster, yes? – SirJosh3917 Jun 27 '17 at 15:07
  • Possible duplicate of [Moving elements in array c#](https://stackoverflow.com/questions/7242909/moving-elements-in-array-c-sharp) – Romano Zumbé Jun 27 '17 at 15:14
  • It seems that you want to swap one element with another on a array? – Tony Jun 27 '17 at 15:16
  • @SirJosh3917 not in every case, if you need to maximize perfomance - try to do it in different ways – yolo sora Jun 27 '17 at 15:17
  • After some testing with the 4 below methods, I found these results: Speed for moveElement: 951, ticks: 4026702 Speed for ShiftRightAt: 18, ticks: 77829 Speed for shiftlist: 44, ticks: 188102 Speed for arrayCopy: 55, ticks: 233153 – SirJosh3917 Jun 27 '17 at 15:27
  • After trying it a bit,the fastest method has a difference in performance depending on the element index. Using your test code, but setting the index at 2000000,`Speed for ShiftRightAt: 509, ticks: 1694567 Speed for shiftlist: 198, ticks: 659088` – Pikoh Jun 27 '17 at 15:44
  • I really don't know at this point. Some methods are faster then others in specific scenarios. – SirJosh3917 Jun 27 '17 at 15:48
  • @SirJosh3917 have a look at the edit in my answer. I think its faster now. – Pikoh Jun 27 '17 at 16:27

5 Answers5

3

your nice drawing gives exactly what you need to write.

public static void ShiftRightAt<T>(T[] array, int index)
{
    if (index < 0 || index >= array.Length) return; // throw exception

    var element = array[index]; // take out the element

    for (int i = index; i > 0; i--)
    {
        array[i] = array[i - 1];
    }

    array[0] = element;
}
M.kazem Akhgary
  • 18,645
  • 8
  • 57
  • 118
1

It's easier using a list. After that, convert it back to an array.

var array = new int[] { 0, 1, 2, 3, 4, 5 };                 
var list = array.ToList();
list.Remove(3);
list.Insert(0, 3);
array = list.ToArray();
Alexandru Pupsa
  • 1,798
  • 4
  • 21
  • 40
  • Don't lists consume more resources then an array? – SirJosh3917 Jun 27 '17 at 15:09
  • List uses an Array under the hood, hidden mostly behind some method-base abstractions to do things such as hide unused elements and grow the array when more space is needed. Having a constant size, this will use an array of 2^(ceiling)log2(N), which should be a trivial jump in most cases – David Jun 27 '17 at 15:12
  • 1
    this will be actually slower (while its more readable) than what OPs having – M.kazem Akhgary Jun 27 '17 at 15:12
1

This is an example using Array.Copy,so it should be fast enough:

int elementAt = 3;
int[] array = { 0, 1, 2, 3, 4, 5 };

int[] arr1=new int[array.Length];
arr1[0] = array[elementAt];
Array.Copy(array, 0, arr1, 1, elementAt);
Array.Copy(array, elementAt+1, arr1, elementAt+1, array.Length-elementAt-1);
//arr1={3, 0, 1, 2, 4, 5}

Edit

I was not satisfied with the results, as i thought the Array.Copy should be faster. I think this version improves speed a lot:

int saved = array[elementAt];
Array.Copy(array, elementAt + 1, array, elementAt, array.Length - elementAt - 1);
Array.Copy(array, 0, array, 1, array.Length - 1);
array[0] = saved;
Pikoh
  • 7,582
  • 28
  • 53
  • using the same testing method ( check OP for method ) here's your results and how you do. https://pastebin.com/a3Fm2AJZ – SirJosh3917 Jun 27 '17 at 16:30
  • So that's an improvement. It's the faster in some test cases,isn't it? – Pikoh Jun 27 '17 at 16:31
  • Yup. Every solution has their strong scenarios and weak scenarios. For example, you did the best in the case where (LOW, HIGH, LOW, and also HIGH, HIGH, LOW) it's a low amount of iterations, a high index size and low array size. – SirJosh3917 Jun 27 '17 at 16:32
  • Also in (LOW, LOW, LOW - HIGH, HIGH, LOW and LOW, HIGH, HIGH) :) – Pikoh Jun 27 '17 at 16:33
  • For LOW LOW LOW ShiftRightAt wins there at *only* 3 ticks. – SirJosh3917 Jun 27 '17 at 16:35
1

Here's an extension method that you could use:

public static int[] MoveValueToFront(this int[] values, int searchValue)
{
    if (values == null || values.Length == 0)
    {
        return values;
    }

    var rest = values.TakeWhile(v => v != searchValue).ToArray();

    if (rest.Length == values.Length)
    {
        return values;
    }

    values[0] = searchValue;
    rest.CopyTo(values, 1);

    return values;
}

Which would allow you to do this:

[TestMethod]
public void TestMoverExtension()
{

    var testValues = new int[] { 0, 1, 2, 3, 4, 5 };

    var result = testValues.MoveValueToFront(3);


    CollectionAssert.AreEqual(new int[] { 3, 0, 1, 2, 4, 5 }, result);
}
P. Roe
  • 2,077
  • 1
  • 16
  • 23
0

If you can't (or don't want to) work with List you could also use the following:

public int[] moveElement(int[] array, int index)
{
    int[] save = new int[] { array[index] };
    var rest = array.Take(index).Concat(array.Skip(index + 1));
    return save.Concat(rest).ToArray();
}

EDIT

If you need this for different data types this is a generic version:

public T[] moveElement<T>(T[] array, int index)
{
    T[] save = new T[] { array[index] };
    var rest = array.Take(index).Concat(array.Skip(index + 1));
    return save.Concat(rest).ToArray();
} 
Romano Zumbé
  • 7,893
  • 4
  • 33
  • 55