TL;DR: I need a way to copy an array with integers, in which the copy will not change the original array, and that will work in Unity.
I am trying to implement the following algorithm: I have an array field with numbers that are editable in the inspector. These numbers indicate the number of enemies of each type to spawn:
public int[] EnemiesToSpawn;
And, for example, I set the array to 3 digits, the index of each in the array corresponds to the index of the object in the array with enemy prefabs.
Then, in the function, I randomly generate enemies, each time decreasing the corresponding number in the array by one (if the element integer is 0, another enemy is selected, and if the integer of all elements becomes 0, the spawn function ends execution).
Everything worked well until I needed to have multiple points on the level, each of which would generate enemies independently. What I did: I added another array, into which I copy the values from the first one every time I need to spawn enemies at a new point, and edited this particular second array instead of the original one (simply by assigning the value via "="). Of course it didn't work, I googled it and realized that arrays in C # are stored as references, not values, so the original array was edited as well.
I tried a lot of options that offer for correct copying (such as System.Array.Copy and others), but for some reason none of them worked in Unity.
The only thing I came up with myself was iterating over in a loop and assigning values separately:
EnemiesToSpawnCurrent = new int [EnemiesToSpawn.Length];
for (int i = 0; i <EnemiesToSpawn.Length; i ++)
{
EnemiesToSpawnCurrent [i] = i;
}
But, this code also does not work correctly for some reason, the numbers do not correspond to those entered in the inspector (most likely the indexes of the elements do not match).
I will be grateful if you tell me how you can optimally solve this problem.
Option A:
int[] a; // original array you want to deep copy
int[] b = new int[a.length]; // your copy
System.Array.Copy(a, b, a.length);
Option B:
int[] a; // original array you want to deep copy
int[] b = (int[]) a.Clone();
edit: in your code, the numbers won't match, because you are assigning them i.
EnemiesToSpawnCurrent = new int [EnemiesToSpawn.Length];
for (int i = 0; i <EnemiesToSpawn.Length; i ++)
{
EnemiesToSpawnCurrent [i] = i; // wrong!
}
this should work:
EnemiesToSpawnCurrent = new int[EnemiesToSpawn.Length];
for (int i = 0; i <EnemiesToSpawn.Length; i ++)
{
EnemiesToSpawnCurrent[i] = EnemiesToSpawn[i]; // copy each value from original to new Array.
}
Explanation: For int Array, this works because Integers are "Value type" and not reference Type. The whole array is Reference Type, so you need to create a new, independent instance. But assigning the values (ints) to the new array will work.
If you however want to copy something like Player[] you would need to create deep copies of the Player instances as well.
There i try to specify bounds of an array:
public string[] scaleChanged()
{
int j =0;
for(int i=0;i<42;i++)
{
if(MinScale == ItemScale[i]) //MinScale is the min value I want to use to start array
{
ItemsScale[j] = MinScale; //ItemScal is an array of 42 string
for(int h =0; h<42-i; h++)
{
ItemScale[j+1] = ItemScale[i];
j++;
if(ItemScale[j] == MaxScale) //MaxScale is my max value I want to use for stop my array
{
return ItemScale[ ???MinScale to MaxScale];
}
}
}
}
}
So I recover 2 value from a server which allow me to specify bounds of my array.
So I try to define a new array with this two values as bounds.I precise this "two values" are always declared anywhere in my ItemScale array (that is why i use comparaison).
If really depends what you are trying to do here. The bounds of an array are fixed at creation, and in the case of a vector (string[] is a vector), it is always zero-based. If you want an actual array, then you'll need to copy out the sub-range into a second array - just new the array of the correct size, and Array.Copy the element range you want - i.e. Array.Copy(source, startIndex, destination, 0, count);. However, there are ways to represent a range without copying:
if the receiver just needs to iterate the data (rather than access it by index), an IEnumerable<T> - i.e. return source.Skip(firstIndex).Take(count);
Span<T> or ReadOnlySpan<T>, i.e. return new Span<string>(source, firstIndex, count) - a "span" works much like an array, and doesn't require any copying, and is allocation-free; the offset etc is applied appropriately; note that once you have a span, .Slice(...) creates smaller and smaller sub-sections inside that span, again without any copying or allocations
one nice thing here is that you can use the span approach as a simpler way of dealing with creating a new array if you want - once you have a [ReadOnly]Span<T>, you can use .ToArray() to create a new array with those contents
Memory<T> or ReadOnlyMemory<T> is effectively "I can give you a span when you want one" - because you can't store a "span" as a field (it is only legal on the stack), but you can store a "memory"
ArraySegment<T> is an older metaphor for expressing an array with offset and count; it relies on the caller doing everything correctly
I have an Array variable. I can use the Rank property to get the number of dimensions and I know that you can use a foreach to visit each element as if the array was flattened. However, I wish to modify elements and change element references. I cannot dynamically create the correct number of for loops and I cannot invalidate an enumerator.
EDIT
Thanks for the comments, sorry about the previous lack of clarity at the end of a long tiring day. The problem:
private void SetMultiDimensionalArray(Array array)
{
for (int dimension = 0; dimension < array.Rank; dimension++)
{
var len = array.GetLength(dimension);
for (int k = 0; k < len; k++)
{
//TODO: do something to get/set values
}
}
}
Array array = new string[4, 5, 6];
SetMultiDimensionalArray(array);
Array array = new string[2, 3];
SetMultiDimensionalArray(array);
I had another look before reading this page and it appears all I need to do is create a list of integer arrays and use the overloads of GetValue and SetValue -
Array.GetValue(params int[] indices)
Array.SetValue(object value, params int[] indices)
Everything seems clear now unless someone can suggest a superior method. svick has linked to this so I will accept this answer barring any further suggestions.
It's hard to tell what exactly do you need, because your question is quite unclear.
But if you have a multidimensional array (not jagged array) whose rank you know only at runtime, you can use GetValue() to get the value at specified indices (given as an array of ints) and SetValue() to set it.
hello i will much apreciate any help.
ok let's see, first i have declare a jagged array like this and the next code
int n=1, m=3,p=0;
int[][] jag_array =new[n];
now my jagged array will have 1 array inside, next y have to fill the array like this:
car=2;
do
{
jag_array[p]= new double[car];
for (int t = 0; t < carac; t++)
{
jag_array[p][t] = variableX;
}
p=p+1
}
while(p==0)
now my jagged array looks like this(also insert some data for this example):
jag_array[0][0]=4
jag_array[0][1]=2
now my question how can i insert a new array whit out losing my previos data if i declare
jag_array[p+1]= new double[car];
i will lose the data from the previos one, i will like to look something likes this:
jag_array[0][0]=4
jag_array[0][1]=2
jag_array[1][0]=5
jag_array[1][1]=6
the reason i did not declare from the begining 2 array is beacuse i dont know how many i am going to use it could be just 1 or 20 and every time i have to create a new array whit out losing the previous data that has been already fill, thaks all for the attention,
The size of an array, once created, is by definition invariable. If you need a variable number of elements, use a List<T> - in your case, probably a List<int[]>.
The only alternative solution would be to created a new array with the new size (and assign that to your jag_array variable) and copy all the previous elements from your old array into the new array. That is unnecessarily complicated code when you can just use List<T>, but if you cannot use List<T> for any reason, here is an example:
// increase the length of jag_array by one
var old_jag_array = jag_array; // store a reference to the smaller array
jag_array = new int[old_jag_array.Length + 1][]; // create the new, larger array
for (int i = 0; i < old_jag_array.Length; i++) {
jag_array[i] = old_jag_array[i]; // copy the existing elements into the new array
}
jag_array[jag_array.Length - 1] = ... // insert new value here
When is it better to use a List vs a LinkedList?
In most cases, List<T> is more useful. LinkedList<T> will have less cost when adding/removing items in the middle of the list, whereas List<T> can only cheaply add/remove at the end of the list.
LinkedList<T> is only at it's most efficient if you are accessing sequential data (either forwards or backwards) - random access is relatively expensive since it must walk the chain each time (hence why it doesn't have an indexer). However, because a List<T> is essentially just an array (with a wrapper) random access is fine.
List<T> also offers a lot of support methods - Find, ToArray, etc; however, these are also available for LinkedList<T> with .NET 3.5/C# 3.0 via extension methods - so that is less of a factor.
Thinking of a linked list as a list can be a bit misleading. It's more like a chain. In fact, in .NET, LinkedList<T> does not even implement IList<T>. There is no real concept of index in a linked list, even though it may seem there is. Certainly none of the methods provided on the class accept indexes.
Linked lists may be singly linked, or doubly linked. This refers to whether each element in the chain has a link only to the next one (singly linked) or to both the prior/next elements (doubly linked). LinkedList<T> is doubly linked.
Internally, List<T> is backed by an array. This provides a very compact representation in memory. Conversely, LinkedList<T> involves additional memory to store the bidirectional links between successive elements. So the memory footprint of a LinkedList<T> will generally be larger than for List<T> (with the caveat that List<T> can have unused internal array elements to improve performance during append operations.)
They have different performance characteristics too:
Append
LinkedList<T>.AddLast(item) constant time
List<T>.Add(item) amortized constant time, linear worst case
Prepend
LinkedList<T>.AddFirst(item) constant time
List<T>.Insert(0, item) linear time
Insertion
LinkedList<T>.AddBefore(node, item) constant time
LinkedList<T>.AddAfter(node, item) constant time
List<T>.Insert(index, item) linear time
Removal
LinkedList<T>.Remove(item) linear time
LinkedList<T>.Remove(node) constant time
List<T>.Remove(item) linear time
List<T>.RemoveAt(index) linear time
Count
LinkedList<T>.Count constant time
List<T>.Count constant time
Contains
LinkedList<T>.Contains(item) linear time
List<T>.Contains(item) linear time
Clear
LinkedList<T>.Clear() linear time
List<T>.Clear() linear time
As you can see, they're mostly equivalent. In practice, the API of LinkedList<T> is more cumbersome to use, and details of its internal needs spill out into your code.
However, if you need to do many insertions/removals from within a list, it offers constant time. List<T> offers linear time, as extra items in the list must be shuffled around after the insertion/removal.
Linked lists provide very fast insertion or deletion of a list member. Each member in a linked list contains a pointer to the next member in the list so to insert a member at position i:
update the pointer in member i-1 to point to the new member
set the pointer in the new member to point to member i
The disadvantage to a linked list is that random access is not possible. Accessing a member requires traversing the list until the desired member is found.
Edit
Please read the comments to this answer. People claim I did not do
proper tests. I agree this should not be an accepted answer. As I was
learning I did some tests and felt like sharing them.
Original answer...
I found interesting results:
// Temporary class to show the example
class Temp
{
public decimal A, B, C, D;
public Temp(decimal a, decimal b, decimal c, decimal d)
{
A = a; B = b; C = c; D = d;
}
}
Linked list (3.9 seconds)
LinkedList<Temp> list = new LinkedList<Temp>();
for (var i = 0; i < 12345678; i++)
{
var a = new Temp(i, i, i, i);
list.AddLast(a);
}
decimal sum = 0;
foreach (var item in list)
sum += item.A;
List (2.4 seconds)
List<Temp> list = new List<Temp>(); // 2.4 seconds
for (var i = 0; i < 12345678; i++)
{
var a = new Temp(i, i, i, i);
list.Add(a);
}
decimal sum = 0;
foreach (var item in list)
sum += item.A;
Even if you only access data essentially it is much slower!! I say never use a linkedList.
Here is another comparison performing a lot of inserts (we plan on inserting an item at the middle of the list)
Linked List (51 seconds)
LinkedList<Temp> list = new LinkedList<Temp>();
for (var i = 0; i < 123456; i++)
{
var a = new Temp(i, i, i, i);
list.AddLast(a);
var curNode = list.First;
for (var k = 0; k < i/2; k++) // In order to insert a node at the middle of the list we need to find it
curNode = curNode.Next;
list.AddAfter(curNode, a); // Insert it after
}
decimal sum = 0;
foreach (var item in list)
sum += item.A;
List (7.26 seconds)
List<Temp> list = new List<Temp>();
for (var i = 0; i < 123456; i++)
{
var a = new Temp(i, i, i, i);
list.Insert(i / 2, a);
}
decimal sum = 0;
foreach (var item in list)
sum += item.A;
Linked List having reference of location where to insert (.04 seconds)
list.AddLast(new Temp(1,1,1,1));
var referenceNode = list.First;
for (var i = 0; i < 123456; i++)
{
var a = new Temp(i, i, i, i);
list.AddLast(a);
list.AddBefore(referenceNode, a);
}
decimal sum = 0;
foreach (var item in list)
sum += item.A;
So only if you plan on inserting several items and you also somewhere have the reference of where you plan to insert the item then use a linked list. Just because you have to insert a lot of items it does not make it faster because searching the location where you will like to insert it takes time.
My previous answer was not enough accurate.
As truly it was horrible :D
But now I can post much more useful and correct answer.
I did some additional tests. You can find it's source by the following link and reCheck it on your environment by your own: https://github.com/ukushu/DataStructuresTestsAndOther.git
Short results:
Array need to use:
So often as possible. It's fast and takes smallest RAM range for same amount information.
If you know exact count of cells needed
If data saved in array < 85000 b (85000/32 = 2656 elements for integer data)
If needed high Random Access speed
List need to use:
If needed to add cells to the end of list (often)
If needed to add cells in the beginning/middle of the list (NOT OFTEN)
If data saved in array < 85000 b (85000/32 = 2656 elements for integer data)
If needed high Random Access speed
LinkedList need to use:
If needed to add cells in the beginning/middle/end of the list (often)
If needed only sequential access (forward/backward)
If you need to save LARGE items, but items count is low.
Better do not use for large amount of items, as it's use additional memory for links.
More details:
Interesting to know:
LinkedList<T> internally is not a List in .NET. It's even does not implement IList<T>. And that's why there are absent indexes and methods related to indexes.
LinkedList<T> is node-pointer based collection. In .NET it's in doubly linked implementation. This means that prior/next elements have link to current element. And data is fragmented -- different list objects can be located in different places of RAM. Also there will be more memory used for LinkedList<T> than for List<T> or Array.
List<T> in .Net is Java's alternative of ArrayList<T>. This means that this is array wrapper. So it's allocated in memory as one contiguous block of data. If allocated data size exceeds 85000 bytes, it will be moved to Large Object Heap. Depending on the size, this can lead to heap fragmentation(a mild form of memory leak). But in the same time if size < 85000 bytes -- this provides a very compact and fast-access representation in memory.
Single contiguous block is preferred for random access performance and memory consumption but for collections that need to change size regularly a structure such as an Array generally need to be copied to a new location whereas a linked list only needs to manage the memory for the newly inserted/deleted nodes.
The difference between List and LinkedList lies in their underlying implementation. List is array based collection (ArrayList). LinkedList is node-pointer based collection (LinkedListNode). On the API level usage, both of them are pretty much the same since both implement same set of interfaces such as ICollection, IEnumerable, etc.
The key difference comes when performance matter. For example, if you are implementing the list that has heavy "INSERT" operation, LinkedList outperforms List. Since LinkedList can do it in O(1) time, but List may need to expand the size of underlying array. For more information/detail you might want to read up on the algorithmic difference between LinkedList and array data structures. http://en.wikipedia.org/wiki/Linked_list and Array
Hope this help,
The primary advantage of linked lists over arrays is that the links provide us with the capability to rearrange the items efficiently.
Sedgewick, p. 91
A common circumstance to use LinkedList is like this:
Suppose you want to remove many certain strings from a list of strings with a large size, say 100,000. The strings to remove can be looked up in HashSet dic, and the list of strings is believed to contain between 30,000 to 60,000 such strings to remove.
Then what's the best type of List for storing the 100,000 Strings? The answer is LinkedList. If the they are stored in an ArrayList, then iterating over it and removing matched Strings whould take up
to billions of operations, while it takes just around 100,000 operations by using an iterator and the remove() method.
LinkedList<String> strings = readStrings();
HashSet<String> dic = readDic();
Iterator<String> iterator = strings.iterator();
while (iterator.hasNext()){
String string = iterator.next();
if (dic.contains(string))
iterator.remove();
}
When you need built-in indexed access, sorting (and after this binary searching), and "ToArray()" method, you should use List.
Essentially, a List<> in .NET is a wrapper over an array. A LinkedList<> is a linked list. So the question comes down to, what is the difference between an array and a linked list, and when should an array be used instead of a linked list. Probably the two most important factors in your decision of which to use would come down to:
Linked lists have much better insertion/removal performance, so long as the insertions/removals are not on the last element in the collection. This is because an array must shift all remaining elements that come after the insertion/removal point. If the insertion/removal is at the tail end of the list however, this shift is not needed (although the array may need to be resized, if its capacity is exceeded).
Arrays have much better accessing capabilities. Arrays can be indexed into directly (in constant time). Linked lists must be traversed (linear time).
This is adapted from Tono Nam's accepted answer correcting a few wrong measurements in it.
The test:
static void Main()
{
LinkedListPerformance.AddFirst_List(); // 12028 ms
LinkedListPerformance.AddFirst_LinkedList(); // 33 ms
LinkedListPerformance.AddLast_List(); // 33 ms
LinkedListPerformance.AddLast_LinkedList(); // 32 ms
LinkedListPerformance.Enumerate_List(); // 1.08 ms
LinkedListPerformance.Enumerate_LinkedList(); // 3.4 ms
//I tried below as fun exercise - not very meaningful, see code
//sort of equivalent to insertion when having the reference to middle node
LinkedListPerformance.AddMiddle_List(); // 5724 ms
LinkedListPerformance.AddMiddle_LinkedList1(); // 36 ms
LinkedListPerformance.AddMiddle_LinkedList2(); // 32 ms
LinkedListPerformance.AddMiddle_LinkedList3(); // 454 ms
Environment.Exit(-1);
}
And the code:
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace stackoverflow
{
static class LinkedListPerformance
{
class Temp
{
public decimal A, B, C, D;
public Temp(decimal a, decimal b, decimal c, decimal d)
{
A = a; B = b; C = c; D = d;
}
}
static readonly int start = 0;
static readonly int end = 123456;
static readonly IEnumerable<Temp> query = Enumerable.Range(start, end - start).Select(temp);
static Temp temp(int i)
{
return new Temp(i, i, i, i);
}
static void StopAndPrint(this Stopwatch watch)
{
watch.Stop();
Console.WriteLine(watch.Elapsed.TotalMilliseconds);
}
public static void AddFirst_List()
{
var list = new List<Temp>();
var watch = Stopwatch.StartNew();
for (var i = start; i < end; i++)
list.Insert(0, temp(i));
watch.StopAndPrint();
}
public static void AddFirst_LinkedList()
{
var list = new LinkedList<Temp>();
var watch = Stopwatch.StartNew();
for (int i = start; i < end; i++)
list.AddFirst(temp(i));
watch.StopAndPrint();
}
public static void AddLast_List()
{
var list = new List<Temp>();
var watch = Stopwatch.StartNew();
for (var i = start; i < end; i++)
list.Add(temp(i));
watch.StopAndPrint();
}
public static void AddLast_LinkedList()
{
var list = new LinkedList<Temp>();
var watch = Stopwatch.StartNew();
for (int i = start; i < end; i++)
list.AddLast(temp(i));
watch.StopAndPrint();
}
public static void Enumerate_List()
{
var list = new List<Temp>(query);
var watch = Stopwatch.StartNew();
foreach (var item in list)
{
}
watch.StopAndPrint();
}
public static void Enumerate_LinkedList()
{
var list = new LinkedList<Temp>(query);
var watch = Stopwatch.StartNew();
foreach (var item in list)
{
}
watch.StopAndPrint();
}
//for the fun of it, I tried to time inserting to the middle of
//linked list - this is by no means a realistic scenario! or may be
//these make sense if you assume you have the reference to middle node
//insertion to the middle of list
public static void AddMiddle_List()
{
var list = new List<Temp>();
var watch = Stopwatch.StartNew();
for (var i = start; i < end; i++)
list.Insert(list.Count / 2, temp(i));
watch.StopAndPrint();
}
//insertion in linked list in such a fashion that
//it has the same effect as inserting into the middle of list
public static void AddMiddle_LinkedList1()
{
var list = new LinkedList<Temp>();
var watch = Stopwatch.StartNew();
LinkedListNode<Temp> evenNode = null, oddNode = null;
for (int i = start; i < end; i++)
{
if (list.Count == 0)
oddNode = evenNode = list.AddLast(temp(i));
else
if (list.Count % 2 == 1)
oddNode = list.AddBefore(evenNode, temp(i));
else
evenNode = list.AddAfter(oddNode, temp(i));
}
watch.StopAndPrint();
}
//another hacky way
public static void AddMiddle_LinkedList2()
{
var list = new LinkedList<Temp>();
var watch = Stopwatch.StartNew();
for (var i = start + 1; i < end; i += 2)
list.AddLast(temp(i));
for (int i = end - 2; i >= 0; i -= 2)
list.AddLast(temp(i));
watch.StopAndPrint();
}
//OP's original more sensible approach, but I tried to filter out
//the intermediate iteration cost in finding the middle node.
public static void AddMiddle_LinkedList3()
{
var list = new LinkedList<Temp>();
var watch = Stopwatch.StartNew();
for (var i = start; i < end; i++)
{
if (list.Count == 0)
list.AddLast(temp(i));
else
{
watch.Stop();
var curNode = list.First;
for (var j = 0; j < list.Count / 2; j++)
curNode = curNode.Next;
watch.Start();
list.AddBefore(curNode, temp(i));
}
}
watch.StopAndPrint();
}
}
}
You can see the results are in accordance with theoretical performance others have documented here. Quite clear - LinkedList<T> gains big time in case of insertions. I haven't tested for removal from the middle of list, but the result should be the same. Of course List<T> has other areas where it performs way better like O(1) random access.
Use LinkedList<> when
You don't know how many objects are coming through the flood gate. For example, Token Stream.
When you ONLY wanted to delete\insert at the ends.
For everything else, it is better to use List<>.
I do agree with most of the point made above. And I also agree that List looks like a more obvious choice in most of the cases.
But, I just want to add that there are many instance where LinkedList are far better choice than List for better efficiency.
Suppose you are traversing through the elements and you want to perform lot of insertions/deletion; LinkedList does it in linear O(n) time, whereas List does it in quadratic O(n^2) time.
Suppose you want to access bigger objects again and again, LinkedList become very more useful.
Deque() and queue() are better implemented using LinkedList.
Increasing the size of LinkedList is much easier and better once you are dealing with many and bigger objects.
Hope someone would find these comments useful.
In .NET, Lists are represented as Arrays. Therefore using a normal List would be quite faster in comparison to LinkedList.That is why people above see the results they see.
Why should you use the List?
I would say it depends. List creates 4 elements if you don't have any specified. The moment you exceed this limit, it copies stuff to a new array, leaving the old one in the hands of the garbage collector. It then doubles the size. In this case, it creates a new array with 8 elements. Imagine having a list with 1 million elements, and you add 1 more. It will essentially create a whole new array with double the size you need. The new array would be with 2Mil capacity however, you only needed 1Mil and 1. Essentially leaving stuff behind in GEN2 for the garbage collector and so on. So it can actually end up being a huge bottleneck. You should be careful about that.
I asked a similar question related to performance of the LinkedList collection, and discovered Steven Cleary's C# implement of Deque was a solution. Unlike the Queue collection, Deque allows moving items on/off front and back. It is similar to linked list, but with improved performance.