35

Good day all

So I know that this is a fairly widely discussed issue, but I can't seem to find a definitive answer. I know that you can do what I am asking for using a List, but that won't solve my issue.

I teach a class in beginner C#. I have a PHP and Java Script background, and thus tend to think in terms of these languages.

I have been looking for the best way to show my students how to add elements to an array on the fly.We can't use Lists, as these are not part of the syllabus that I currently teach (although they do come in later in the semester).

I am thus looking for the simplest way to perform a Java array.push(newValue) type scenario that will be understandable to novice coders without teaching them bad practice.

Here is how I have been approaching the problem so far:

for (int i = 0; i < myArray.Length; i++)
{
   if(myArray[i] == null)
   {
       myArray[i] = newValue;
       break;
   }
}

I just need to know if this is an acceptable approach, if I am teaching them any bad practices, or if there is a better / simpler way of achieving my goal.

EDIT The crux of the matter is that the element needs to be added into the first empty slot in an array, lie a Java push function would do.

Any advice would be greatly appreciated.

phunder
  • 1,607
  • 3
  • 17
  • 33
  • 3
    That is not pushing to an array. It is merely **assigning** to it. – mjwills Jul 25 '18 at 05:16
  • Possible duplicate of [add an element at a certain position of a char array?](https://stackoverflow.com/questions/51490375/add-an-element-at-a-certain-position-of-a-char-array) – mjwills Jul 25 '18 at 05:17
  • 3
    @phunder you dont push to an array in C#. Array are fix sized. – aloisdg Jul 25 '18 at 05:27
  • @mjwills I realize that I am assigning yes. My question is, can you into an array push in C#, and if not is this an acceptable alternative, or is there a better way (without replacing the array with a list please) – phunder Jul 25 '18 at 05:28
  • 1
    @phunder: do *arrays* (not lists) in Java have method `push` and allow to *add* items? Could you post a proof? I'm not a Java guy, and tried to search `push` docs to help you find C# equivalent, but everything I found is that *arrays* in Java behave the same as in C#. Did you mean JS instead of Java? – Dennis Jul 25 '18 at 05:37
  • 1
    `can you into an array push in C#` No. – mjwills Jul 25 '18 at 05:40
  • 3
    @phunder I would avoid trying to use an array in this way, especially if you're teaching beginners. Arrays are fixed-size in C#, the lesson should be that different data types are suited for different tasks. – Kyle Jul 25 '18 at 05:44
  • @Dennis thank you yes, I have more JaveScript and PHP experience than anything else, and must have gotten my wires crossed. Will edit my post to make more sense. Apologies! – phunder Jul 25 '18 at 05:46
  • @phunder I may be worth reviewing the implementation of `IEnumerable.Append(T item)` (where `T` is a value type). – Brett Caswell Jul 25 '18 at 05:51
  • If what you're trying to do is teach people how to use a dynamically sized array in .net, add `List` to your syllabus. That is the correct tool for the job, and they will need to know it. Also, as far as I know, `push` always appends an element, it does not replace the first `null` value. – George Helyar Jul 26 '18 at 05:19

13 Answers13

30

array.push is like List<T>.Add. .NET arrays are fixed-size so you can't actually add a new element. All you can do is create a new array that is one element larger than the original and then set that last element, e.g.

Array.Resize(ref myArray, myArray.Length + 1);
myArray[myArray.GetUpperBound(0)] = newValue;

EDIT:

I'm not sure that this answer actually applies given this edit to the question:

The crux of the matter is that the element needs to be added into the first empty slot in an array, lie a Java push function would do.

The code I provided effectively appends an element. If the aim is to set the first empty element then you could do this:

int index = Array.IndexOf(myArray, null);

if (index != -1)
{
    myArray[index] = newValue;
}

EDIT:

Here's an extension method that encapsulates that logic and returns the index at which the value was placed, or -1 if there was no empty element. Note that this method will work for value types too, treating an element with the default value for that type as empty.

public static class ArrayExtensions
{
    public static int Push<T>(this T[] source, T value)
    {
        var index = Array.IndexOf(source, default(T));

        if (index != -1)
        {
            source[index] = value;
        }

        return index;
    }
}
jmcilhinney
  • 50,448
  • 5
  • 26
  • 46
  • 3
    This would work, but I am not sure that students will enjoy. :) – aloisdg Jul 25 '18 at 05:30
  • Thank you for the suggestion. I agree with @aloisdg that this might be a bit complicated for novices however – phunder Jul 25 '18 at 05:34
  • I like your second suggestion. This seems less cumbersome than my own approach. Thank you kindly! – phunder Jul 25 '18 at 05:40
  • 6
    Please be aware that this will only work if the type of the array is a reference type or nullable value type. It can't work for standard value types because they cannot be `null`. – jmcilhinney Jul 25 '18 at 05:42
  • I was about to say that @jmcilhinney – Brett Caswell Jul 25 '18 at 05:43
  • 1
    For the record, the edit to the answer was added after my previous comment, so the edit can work for standard value types, as long as you consider the default value of the type, e.g. zero for numeric types, to be "empty". – jmcilhinney Dec 16 '20 at 00:03
9

Your question is a little off the mark. In particular, you say "that the element needs to be added into the first empty slot in an array, lie (sic) a Java push function would do."

  1. Java's Array does not have a push operation - JavaScript does. Java and JavaScript are two very different languages
  2. JavaScript's push function does not behave as you describe. When you "push" a value into a JavaScript array, the array is extended by one element, and that new element is assigned the pushed value, see: Mozilla's Array.prototype.push function docs

The verb "Push" is not something that is used with an Array in any language that I know of except JavaScript. I suspect that it's only in JavaScript because it could be there (since JavaScript is a completely dynamic language). I'm pretty sure it wasn't designed in intentionally.

A JavaScript-style Push operation in C# could be written in this somewhat inefficient manner:

int [] myArray = new int [] {1, 2, 3, 4};
var tempList = myArray.ToList();
tempList.Add(5);
myArray = tempList.ToArray();   //equiv: myArray.Push(5);

"Push" is used in some types of containers, particularly Stacks, Queues and Deques (which get two pushes - one from the front, one from the back). I urge you not to include Push as a verb in your explanation of arrays. It adds nothing to a CS student's vocabulary.

In C#, as in most traditional procedural languages, an array is a collection of elements of a single type, contained in a fixed length contiguous block of memory. When you allocate an array, the space for every array element is allocated (and, in C# those elements are initialized to the default value of the type, null for reference types).

In C#, arrays of reference types are filled with object references; arrays of value types are filled with instances of that value type. As a result, an array of 4 strings uses the same memory as an array of 4 instance of your application class (since they are both reference types). But, an array of 4 DateTime instances is significantly longer that of an array of 4 short integers.

In C#, an instance of an array is an instance of System.Array, a reference type. Arrays have a few properties and methods (like the Length property). Otherwise, there isn't much you can do with an array: you can read (or write) from (or to) individual elements using an array index. Arrays of type T also implement IEnumerable<T>, so you can iterate through the elements of an array.

Arrays are mutable (the values in an array can be written to), but they have a fixed length - they can't be extended or shortened. They are ordered, and they can't be re-arranged (except by swizzling the values manually).

C# arrays are covariant. If you were to ask the C# language designers, this would be the feature they regret the most. It's one of the few ways you can break C# type safety. Consider this code (assuming that Cat and Dog classes inherit from Animal):

Cat[] myCats = new Cat[]{myCat, yourCat, theirCat};
Animal[] animals = (Animal[]) myCats;     //legal but dangerous
animals[1] = new Dog();                   //heading off the cliff
myCats[1].Speak();                        //Woof!

That "feature" is the result of the lack of generic types and explicit covariance/contravariance in the initial version of the .NET Framework and the urge to copy a Java "feature".

Arrays do show up in many core .NET APIs (for example, System.Reflection). They are there, again, because the initial release did not support generic collections.

In general, an experienced C# programmer will not use many arrays in his applications, preferring to use more capable collections such as List<T>, Dictionary<TKey, TValue>, HashSet<T> and friends. In particular, that programmer will tend to pass collections around using IEnumerable<T> an interface that all collections implement. The big advantage of using IEnumerable<T> as parameters and return types (where possible and logical) is that collections accessed via IEnumerable<T> references are immutable. It's kinda-sorta like using const correctly in C++.

One thing you might consider adding in to your lectures on arrays - after everyone has mastered the basics - is the new Span<T> type. Spans may make C# arrays useful.

Finally, LINQ (Language Integrated Query) introduced a lot of functionality to collections (by adding Extension Methods to IEnumerable<T>). Make sure your student do not have a using System.Linq; statement up at the top of their code - mixing LINQ in to a beginning student's class on arrays would bewilder him or her.

BTW: what kind of class is it you teach? At what level?

Flydog57
  • 6,851
  • 2
  • 17
  • 18
  • 1
    The problem with `myArray = myArray.ToList().Add(5).ToArray(); ` is that `Add()` has return type of `void`. – Wiktor Zychla Feb 13 '20 at 20:32
  • @WiktorZychla: Thanks. Fixed that. The old code was a lot easier to read (even if it didn't compile). – Flydog57 Feb 13 '20 at 21:21
  • Yeah, that's unfortunate some simple methods like `Add` aren't designed to be called fluently. – Wiktor Zychla Feb 14 '20 at 07:55
  • 1
    If you're going to go Linq, might as well skip `ToList()`. Just `myArray.Append(5).ToArray()` will do. Of course `Append(5)` is not appending to the array, it's creating an enumeration that walks the array followed by `5`, hence the need for `ToArray()` afterward – Ben Voigt Sep 29 '20 at 15:49
5

As said before, List provides functionality to add elements in a clean way, to do the same with arrays, you have to resize them to accomodate extra elements, see code below:

int[] arr = new int[2];
arr[0] = 1;
arr[1] = 2;
//without this line we'd get a exception
Array.Resize(ref arr, 3);
arr[2] = 3;

Regarding your idea with loop:

elements of an array are set to their default values when array is initialized. So your approach would be good, if you want to fill "blanks" in array holding reference types (which have default value null).

But it wouldn't work with value types, as they are initialized with 0!

Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69
  • Thank you for the information! I did not consider that the default value could be other than null! – phunder Jul 25 '18 at 05:42
5

There is another way to do this, which is fitting perfectly for extension class.

public static void Push<T>(ref T[] table, object value)
{
    Array.Resize(ref table, table.Length + 1);
    table.SetValue(value, table.Length - 1);
}

What is going on here, is that we are resizing and then setting value for the new element created by Array.Resize(...) method.

Here is a snippet with example usage.

Mondonno
  • 161
  • 1
  • 15
4

The is no array.push(newValue) in C#. You don't push to an Array in C#. What we use for this is a List<T>. What you may want to consider (for teaching purpose only) is the ArrayList (no generic and it is a IList, so ...).

static void Main()
{
    // Create an ArrayList and add 3 elements.
    ArrayList list = new ArrayList();
    list.Add("One"); // Add is your push
    list.Add("Two");
    list.Add("Three");
}
aloisdg
  • 22,270
  • 6
  • 85
  • 105
  • Thank you for your comment. Unfortunately I do not want to confuse my novice students with new data types at this time. I just need to know if my approach is acceptable, or if there are any back practices that I am teaching in the process. – phunder Jul 25 '18 at 05:33
  • @phunder Without another data structure, you are going to have a problem. Array are not the structure you are looking for. – aloisdg Jul 25 '18 at 05:36
  • @mjwills Indeed. I really think OP should use List too. – aloisdg Jul 25 '18 at 06:06
  • 1
    @phunder, please don't confuse your novice students by using the verb *push* with arrays. Yeah, JavaScript arrays have a push, but that's not really a native concept for arrays in just about any language. Push is useful in Queues, Stacks and Deques, but not arrays. If you want to see how to implement a JavaScript-style Array.Push, see my answer. But, use it as an example, not a fundamental operation. – Flydog57 Jul 27 '18 at 03:33
4

C# is a little different in this respect with JavaScript. Because of the strict checks, you define the size of the array and you are supposed to know everything about the array such as its bounds, where the last item was put and what items are unused. You are supposed to copy all the elements of the array into a new, bigger one, if you want to resize it.

So, if you use a raw array, there's no other way other than to maintain the last empty, available index assign items to the array at this index, like you're already doing.

However, if you'd like to have the runtime maintain this information and completely abstract away the array, but still use an array underneath, then C# provides a class named ArrayList that provides this abstraction.

The ArrayList abstracts a loosely typed array of Objects. See the source here.

It takes care of all the issues like resizing the array, maintaining the last index that is available, etc. However, it abstracts / encapsulates this information from you. All you use is the ArrayList.

To push an item of any type into the underlying array at the end of the underlying array, call the Add method on the ArrayList like so:

/* you may or may not define a size using a constructor overload */
var arrayList = new ArrayList(); 

arrayList.Add("Foo");

EDIT: A note about type restriction

Like every programming language and runtime does, C# categorizes heap objects from those that will not go on the heap and will only stay on the function's argument stack. C# notes this distinction by the name Value types vs. Reference types. All things whose value goes on the stack are called Value types, and those that will go on the heap are called Reference types. This is loosely similar to JavaScript's distinction between objects and literals.

You can put anything into an ArrayList in C#, whether the thing is a value type or a reference type. This makes it closest to the JavaScript array in terms of typelessness, although neither of the three -- the JavaScript array, the JavaScript language and the C# ArrayList -- are actually type-less.

So, you could put a number literal, a string literal, an object of a class you made up, a boolean, a float, a double, a struct, just about anything you wanted into an ArrayList.

That is because the ArrayList internally maintains and stores all that you put into it, into an array of Objects, as you will have noted in my original answer and the linked source code.

And when you put something that isn't an object, C# creates a new object of type Object, stores the value of the thing you put into the ArrayList into this new Object type object. This process is called boxing and isn't very much unlike the JavaScript boxing mechanism.

For e.g. in JavaScript, while you could use a numeric literal to invoke a function on the Number object, you couldn't add something to the number literal's prototype.

// Valid javascript
var s = 4.toString();

// Invalid JavaScript code
4.prototype.square = () => 4 * 4;
var square = 4.square();

Just like JavaScript boxes the numeric literal 4 in the call to the toString method, C# boxes all things that are not objects into an Object type when putting them into an ArrayList.

var arrayList = new ArrayList();

arrayList.Add(4); // The value 4 is boxed into a `new Object()` first and then that new object is inserted as the last element in the `ArrayList`.

This involves a certain penalty, as it does in the case of JavaScript as well.

In C#, you can avoid this penalty as C# provides a strongly typed version of the ArrayList, known as the List<T>. So it follows that you cannot put anything into a List<T>; just T types.

However, I assume from your question's text that you already knew that C# had generic structures for strongly typed items. And your question was to have a JavaScript like data structure exhibiting the semantics of typelessness and elasticity, like the JavaScript Array object. In this case, the ArrayList comes closest.

It is also clear from your question that your interest was academic and not to use the structure in a production application.

So, I assume that for a production application, you would already know that a generic / strongly typed data structure (List<T> for example) is better performing than its non-typed one (ArrayList for example).

Water Cooler v2
  • 32,724
  • 54
  • 166
  • 336
  • 2
    `ArrayList` is not what you should be using in any modern C# program. `List` is its replacement and should be favored in basically all cases. – Kyle Jul 25 '18 at 05:43
  • @Kyle Yes, but his question is not about the differences between strongly typed and loosely typed data structures. His question is very clear and is about a similar method in C# like the `push` on the `Array` object in JavaScript. – Water Cooler v2 Jul 25 '18 at 05:44
  • This "C# categorizes heap objects from those that will not go on the heap and will only stay on the function's argument stack. C# notes this distinction by the name Value types vs. Reference types. " is horribly incorrect. The heap contains many many instances of value types. – Ben Voigt Sep 29 '20 at 15:50
  • @BenVoigt You mean the heap might contain value types other than those that are contained in reference types? Could you please give me a few examples? – Water Cooler v2 Sep 30 '20 at 01:46
  • @WaterCoolerv2: The existence of "those that are contained in reference types" is exactly why **your claim that they only live on the function argument stack is wrong**. There are at least three flavors of "contained in reference types": Boxing, member variables (fields), and array elements. – Ben Voigt Sep 30 '20 at 15:06
2

This is acceptable as assigning to an array. But if you are asking for pushing, I am pretty sure its not possible in array. Rather it can be achieved by using Stack, Queue or any other data structure. Real arrays doesn't have such functions. But derived classes such as ArrayList have it.

1

As per comment "That is not pushing to an array. It is merely assigning to it"

If you looking for the best practice to assign value to array then its only way that you can assign value.

Array[index]= value;

there is only way to assign value when you do not want to use List.

Anant Dabhi
  • 10,864
  • 3
  • 31
  • 49
  • As stated, a list will not work as we have yet to cover List with this group. I will do so later in the semester, but for now I want to know how to show them basic use of array management. – phunder Jul 25 '18 at 05:26
  • @phunder aray management ok but you wont be able to push new value to your array. – aloisdg Jul 25 '18 at 05:28
  • @phunder. When did push become part of basic array management? – jaket Jul 25 '18 at 05:28
  • @jaket well this is what I need to know. In Java and other languages it is. If it is not pat of C#, I just need to know if my approach is an acceptable way to go about things for novices until we reach lists in the syllabus. – phunder Jul 25 '18 at 05:30
  • @phunder. It is my understanding that push is a part of ArrayList in Java. Not Array. ArrayList in C# has the Insert function which is equivalent – jaket Jul 25 '18 at 05:43
1

I don't think there is another way other than assigning value to that particular index of that array.

0

There are couple of ways this can be done.

First, is converting to list and then to array again:

List<int> tmpList = intArry.ToList();
tmpList.Add(anyInt);
intArry = tmpList.ToArray();

Now this is not recommended as you convert to list and back again to array. If you do not want to use a list, you can use the second way which is assigning values directly into the array:

int[] terms = new int[400];
for (int runs = 0; runs < 400; runs++)
{
    terms[runs] = value;
}

This is the direct approach and if you do not want to tangle with lists and conversions, this is recommended for you.

Barr J
  • 10,636
  • 1
  • 28
  • 46
  • Thank you for the suggestion. As stated, I am trying to stay away from lists at the moment. Your second suggestion seems to add the same value into each space however? Not sure I see the usefulness? – phunder Jul 25 '18 at 05:38
  • I stated for you the two common methods, this is for your suggestion as you are teaching novices right now, overloading them with information is not smart in my opinion. – Barr J Jul 25 '18 at 05:40
  • 3
    `As stated, I am trying to stay away from lists at the moment.` @phunder the downside of that is that you are teaching the students the **wrong** way to attack the problem. In C#, the _standard_ way to solve this is with a `List`. The only reason why you might teach this is a precursor to why `List` is useful. "Ok students, that was hard wasn't it? What if there was a type that was better at solving this problem? Well it turns out there is! And today we will learn about `List`". – mjwills Jul 25 '18 at 05:42
-3

Check out this documentation page: https://msdn.microsoft.com/en-us/library/ms132397(v=vs.110).aspx

The Add function is the first one under Methods.

Joshua M. Moore
  • 381
  • 6
  • 20
-3

I don't understand what you are doing with the for loop. You are merely iterating over every element and assigning to the first element you encounter. If you're trying to push to a list go with the above answer that states there is no such thing as pushing to a list. That really is getting the data structures mixed up. Javascript might not be setting the best example, because a javascript list is really also a queue and a stack at the same time.

Joshua M. Moore
  • 381
  • 6
  • 20
-3

I surggest using the CopyTo method, so here is my two cent on a solution that is easy to explain and simple. The CopyTo method copies the array to another array at a given index. In this case myArray is copied to newArr starting at index 1 so index 0 in newArr can hold the new value.

"Push" to array online demo

var newValue = 1;
var myArray = new int[5] { 2, 3, 4, 5, 6 };
var newArr = new int[myArray.Length + 1];

myArray.CopyTo(newArr, 1);
newArr[0] = newValue;
    
//debug
for(var i = 0; i < newArr.Length; i++){
    Console.WriteLine(newArr[i].ToString());
}

//output
1
2
3
4
5
6
Kasper Jensen
  • 548
  • 5
  • 12