75

If I have an array with 12 elements and I want a new array with that drops the first and 12th elements. For example, if my array looks like this:

__ __ __ __ __ __ __ __ __ __ __ __
a  b  c  d  e  f  g  h  i  j  k  l
__ __ __ __ __ __ __ __ __ __ __ __

I want to either transform it or create a new array that looks like

__ __ __ __ __ __ __ __ __ __

b  c  d  e  f  g  h  i  j  k 
__ __ __ __ __ __ __ __ __ __

I know I can do it by iterating over them. I was just wondering if there was a cleaner way built into C#.

1
  • Isn't "j" the 10th element in the array though? Or did you mean first and last elements? Commented Nov 24, 2009 at 20:07

10 Answers 10

119

LINQ is your friend. :)

var newArray = oldArray.Skip(1).Take(oldArray.Length - 2).ToArray();

Somewhat less efficient than manually creating the array and iterating over it of course, but far simpler.

The slightly lengthier method that uses Array.Copy is the following.

var newArray = new int[oldArray.Count - 2];
Array.Copy(oldArray, 1, newArray, 0, newArray.Length);
Sign up to request clarification or add additional context in comments.

4 Comments

I really liked your original answer. LINQ has been my friend for sometime. I'd just never used skip and take. Thanks.
@L. Moser: No problem - changed back too. :) And yeah, I think I discover a new useful LINQ method every week or so.
Wouldn't this be simpler if you did the Skip after the Take? Like: oldArray.Take(oldArray.Length - 1).Skip(1).ToArray()? Either way are likely equal in effeciency.
Not a good application of LINQ. If you're already down at the char array level then do it right.
40

Linq is all nice and snazzy, but if you're looking for a 1-liner you could just throw together your own utility functions:

static class ArrayUtilities
{
    // create a subset from a range of indices
    public static T[] RangeSubset<T>(this T[] array, int startIndex, int length)
    {
        T[] subset = new T[length];
        Array.Copy(array, startIndex, subset, 0, length);
        return subset;
    }

    // create a subset from a specific list of indices
    public static T[] Subset<T>(this T[] array, params int[] indices)
    {
        T[] subset = new T[indices.Length];
        for (int i = 0; i < indices.Length; i++)
        {
            subset[i] = array[indices[i]];
        }
        return subset;
    }
}

So then you could do the following:

        char[] original = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };

        // array containing 'b' - 'f'
        char[] rangeSubset = original.RangeSubset(1, original.Length - 2);

        // array containing 'c', 'd', and 'f'
        char[] specificSubset = original.Subset(2, 3, 5);

Comments

32

C# 8 has a Range and Index type

char[] a = { 'a', 'b', 'c',  'd',  'e',  'f',  'g',  'h',  'i',  'j',  'k',  'l' };
Index i1 = 1;  // number 1 from beginning
Index i2 = ^1; // number 1 from end
var slice = a[i1..i2]; // { 'b','c','d','e','f','g','h','i','j' }

Comments

11

You can use ArraySegment<T> structure like below:

var arr = new[] { 1, 2, 3, 4, 5 };
var offset = 1;
var count = 2;
var subset = new ArraySegment<int>(arr, offset, count)
             .ToArray(); // output: { 2, 3 }

Check here for an extension method that makes use of it even easier.

Comments

6

You can do this with Array.Copy or LINQ.

var letters = string[] { "a", "b", "c", "d", "e", "f", "g", "h", "i" };

int length = letters.Length - 2;
var items = new string[length];
Array.Copy(letters, 1, items, 0, length);
// or
var items = letters.Skip(1).Take(length).ToArray();

Comments

3

Array.Copy() will do that for you, but you still have to create your new array with its correct size.

Comments

1
string[] s = initialize the array...

var subset = s.Skip(1).Take(s.Length - 2).ToArray();

Comments

0

If you want to avoid manually indexing the array. Don't try to pull request that anywhere though:

var newArray = oldArray.Skip(1).Reverse().Skip(1).Reverse().ToArray()

1 Comment

This doesn't appear to drop the last element.
0

Using the ReadOnlySpan struct the code of the substr for array may look like following:

var subArray = input.AsSpan(offset, length).ToArray();

Comments

0

LINQ has proved to be extremely slow regarding demanding operations in my tests. Array.Copy as shown in the accepted answer is much faster. however, the fastest method so far to achieve your goal is by doing this:

var sub = input[startIndex..endIndex];

(note that there are two dots between the start and end index)

I don't know why no one talks about this feature, please tell me if there is something wrong with this method.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.