Shift items in array up in an array with Array.Copy [duplicate] - c#

This question already has an answer here:
Move/Shift Objects in array up then move the first element to the last index [closed]
(1 answer)
Closed 5 years ago.
Trying to using Array.Copy in the Unity Monodevelop environment, specifically what I'm trying to do is move a value from the first slot of the array into a holder variable, then move every value in the array forward one slot, then move the value from the holder variable back into the Array in the last slot. My relevant code is as follows:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class TurnController : MonoBehaviour {
//Array will hold all units (Being that they all have the EidolonClass script attached), then will be sorted by Speed, descending
private EidolonClass[] AllUnitArray;
...
void Awake(){
//Find anything with the EidolonClass and then add it to the Array
AllUnitArray = FindObjectsOfType (typeof(EidolonClass)) as EidolonClass[];
//Sort the array by speed, descending (Highest speed listed first)
Array.Sort (AllUnitArray, delegate(EidolonClass one, EidolonClass two) {
return two.Speed.CompareTo(one.Speed);
});
}
void pushArray(){
EidolonClass store = AllUnitArray [0];
for(int i=1;i<=AllUnitArray.Length;i++){
Array.Copy (AllUnitArray, i, AllUnitArray, i-1, AllUnitArray.Length-1);
}
AllUnitArray [AllUnitArray.Length] = store;
for(int i=0;i<=AllUnitArray.Length;i++) {
Debug.Log (AllUnitArray[i].name.ToString ());
}
}
void Update () {
if (Input.GetKeyDown (KeyCode.K)) {
pushArray ();
}
}
This code compiles in Monodevelop, but when I try to run this section of my script, it returns the following error:
ArgumentException: length
System.Array.Copy (System.Array sourceArray, Int32 sourceIndex, System.Array destinationArray, Int32 destinationIndex, Int32 length) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System/Array.cs:971)
TurnController.pushArray () (at Assets/Scripts/Battle Scripts/TurnController.cs:54)
TurnController.Update () (at Assets/Scripts/Battle Scripts/TurnController.cs:37)

Your exception occurs because you are trying to copy the same length multiple times, but with new starting offsets each time. To shift the contents of the array, a single call to Array.Copy() would suffice.
Something like this:
void pushArray(){
EidolonClass store = AllUnitArray [0];
Array.Copy (AllUnitArray, 1, AllUnitArray, 0, AllUnitArray.Length - 1);
AllUnitArray[AllUnitArray.Length - 1] = store;
for(int i=0;i<=AllUnitArray.Length;i++) {
Debug.Log (AllUnitArray[i].name.ToString ());
}
}
That said, an array doesn't seem like the best data structure here, if you want to be able to "shift" the contents. If you were using a Queue<EidolonClass> object, then you could just Dequeue() the first element and then Enqueue() the same element to put it at the back of the list.
Personally, I wouldn't bother with either. Instead of trying to shuffle your data around, just keep an index of which element's turn is current. Increment the index to move to the next element's turn. If you reach the end of the array (i.e. the index value is equal to AllUnitArray.Length), then set the index back to 0.
Actually, the Queue<T> class does exactly that internally anyway. So if you like the semantics of the Queue<T> class, it's about the same implementation-wise.

Related

Can we copy the content of an array to another array in languages likes C# and C++ [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
Basically, I have a simple question that I stumbled across.
Code:
// Self implementation of
// the Vector Class in C++
#include <bits/stdc++.h>
using namespace std;
template <typename T> class vectorClass
{
// arr is the integer pointer
// which stores the address of our vector
T* arr;
// capacity is the total storage
// capacity of the vector
int capacity;
// current is the number of elements
// currently present in the vector
int current;
public:
// Default constructor to initialise
// an initial capacity of 1 element and
// allocating storage using dynamic allocation
vectorClass()
{
arr = new T[1];
capacity = 1;
current = 0;
}
// Function to add an element at the last
void push(T data)
{
// if the number of elements is equal to the
// capacity, that means we don't have space to
// accommodate more elements. We need to double the
// capacity
if (current == capacity) {
T* temp = new T[2 * capacity];
// copying old array elements to new array
for (int i = 0; i < capacity; i++) {
temp[i] = arr[i];
}
// deleting previous array
delete[] arr;
capacity *= 2;
arr = temp;
}
// Inserting data
arr[current] = data;
current++;
}
// function to add element at any index
void push(int data, int index)
{
// if index is equal to capacity then this
// function is same as push defined above
if (index == capacity)
push(data);
else
arr[index] = data;
}
// function to extract element at any index
T get(int index)
{
// if index is within the range
if (index < current)
return arr[index];
}
// function to delete last element
void pop() { current--; }
// function to get size of the vector
int size() { return current; }
// function to get capacity of the vector
int getcapacity() { return capacity; }
// function to print array elements
void print()
{
for (int i = 0; i < current; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
};
Question:
In the above code, The Push method has a statement arr = temp; What does that statement mean?
Is it that they are trying to copy the content of array temp to arr?
What if the arr is of static type? Would simply copying the content of one array to another array like this work? Or will it work with dynamic array?
Would it work the same in programming language such a C#?
In C++ we need to manage the dynamic memory, it's different with C#
In the above code, The Push method has a statement arr = temp; What does that statement mean? Is it that they are trying to copy the content of array temp to arr?
It just means copy the pointer temp to arr, no array copy happened here. It's a type of ownership transfer, the dynamic memory handled by temp has been transferred to arr.
What if the arr is of static type? Would simply copying the content of one array to another array like this work? Or will it work with a dynamic array?
What do you mean by static type? All variables in C++ have a static type, all arrays need to be explicitly copied by using memcpy or std::copy. You may also have a look at the std::vector container, in C++ we don't use dynamic arrays too often, your code isn't modern C++ style, we prefer to use containers other than manager dynamic arrays (This keep us away from memory leaking, some kinds of memory corruption). We can use the = to copy vectors, it's much easier to use and safer.
Would it work the same in a programming language such a C#?
For C# you can reference this great answer. In addition to not needing to manage memory, to some extent, it is similar to C++.

how to remove a specific game object (that is in an array) from a list?

my goal with the code is to have multiple skulls appear on screen for comparison. Depending on number of skulls on screen (1-6) they change position and size, Ive done this through the use of an array of gameObjects (the skulls) and a list that can keep track of which skull is in which "position".
The code works if you are adding, but runs into problems when you remove the object. It "works" on RemoveAt only if you remove the GameObjects in the same order that they were added. IE: The list is always removing element 0(first item in list) rather than the specific gameObject that is instigating the RemoveAt function.
While I have found many answers on how to remove specific individual gameObjects, They dont work since my gameObjects are in an array- I cant simply say remove gameObject name. Which leads me to my question of how to remove a specific gameObject[] from a list?
either remove or removeAll run these two errors:
error CS1502: The best overloaded method match for System.Collections.Generic.List<UnityEngine.GameObject>.RemoveAll(System.Predicate<UnityEngine.GameObject>)' has some invalid arguments.
Error CS1503: Argument#1' cannot convert int' expression to typeSystem.Predicate'
Here are my two scripts for all this:
Script on each bird skull named birdController:
public int myBirdID;
public int orderInList;
//bool to keep track of object active or not
public bool whoAmIReally;
//potentially redundant; allows game object to see if hes on or not
public GameObject IAmMe;
// Use this for initialization
void Start () {
//fixingIntOrder();
}
public void OnEnable(){
//when object is on check bool
whoAmIReally = true;
Debug.Log("IM ON");
}
public void OnDisable(){
//when object is turned off uncheck bool, change list value to 0
//**this wont change actual list order or value in cubeplacement script- my hope is that it might have- likely missing a step somewhere
whoAmIReally = false;
orderInList = 0;
Debug.Log("IMOFF");
}
Script on empty with all of my array and list info named cubePlacement:
public int numberSkullOnScreen;
public bool[] skullOn;
public GameObject[] allSkulls;
public GameObject listHolder;
public List<GameObject> birdsOnScreen = new List<GameObject>();
//declaring the script to avoid NullReferenceEcxeption where I reference it
public birdController _birdController;
// Use this for initialization
void Start () {
//only way I can get my list to work: have an object act as a placeholder onStart
birdsOnScreen.Add(listHolder);
}
//turning on and off the skulls
public void toggleBirdSkull(int mySkull){
if (skullOn[mySkull] == false){
//set specific gameObject active
allSkulls[mySkull].SetActive(true);
//make skull on bool true
skullOn[mySkull] = true;
//add one to the number on screen
numberSkullOnScreen++;
//reference int orderInList from Bird controller script
allSkulls[mySkull].gameObject.GetComponent<birdController>().orderInList = numberSkullOnScreen;
//add skull to list when turned on THIS WORKS YAY
birdsOnScreen.Add(allSkulls[mySkull]);
//Run function to place skulls
placementSkulls();
}
else{
allSkulls[mySkull].SetActive(false);
skullOn[mySkull] = false;
numberSkullOnScreen--;
//remove skull from list when turned off-- THIS DOESNT WORK...
birdsOnScreen.RemoveAt(allSkulls[mySkull].gameObject.GetComponent<birdController>().orderInList);
//Run function to place skulls based on the int number skulls on screen
placementSkulls();
}
}
Have you tried to remove objects using Remove method?
Like this:
birdsOnScreen.Remove (allSkulls[mySkull]);
Your birdsOnScreen.RemoveAt version also looks correct.
If you want to use RemoveAll method, you should pass predicate, which returns bool, eg:
birdsOnScreen.RemoveAll (bird => { return bird == allSkulls[mySkull]; } );
I would suggest to use Remove in your case, since you know the object you're removing.
Read more here: https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.remove?view=netframework-4.7.2
Also, try to increase your numberSkullOnScreen after you assign its value to the object's property:
allSkulls[mySkull].gameObject.GetComponent<birdController>().orderInList = numberSkullOnScreen;
numberSkullOnScreen++;
This way you won't need to use a placeholder anymore, because your indices will be correct.
I guess you're looking for a similar function like in an List. You could use this:
public static void RemoveAt<T>(ref T[] arr, int index) {
for (int a = index; a < arr.Length - 1; a++)
{
arr[a] = arr[a + 1];
}
Array.Resize(ref arr, arr.Length - 1);
}
or if you know the Object:
public static T[] RemoveObjectArray<T> (this T[] arr, T ObjToRemove) {
int numIdx = System.Array.IndexOf(arr, ObjToRemove);
if (numIdx == -1) return arr;
List<T> tmp = new List<T>(arr);
tmp.RemoveAt(numIdx);
return tmp.ToArray();
}

Sorting INT variables C#

I am just beginning with programming in c#;
I got a list of int variables that I want to sort, and find the number 1.
int Weapon_Count1, Weapon_Count2, Weapon_Count3, Weapon_Count4, Weapon_Count5, Weapon_Count6, Weapon_Count7, Weapon_Count8, Weapon_Count9
do I need to do this with an array?
By using the yellow book of C# I found out how to make an array, but I can't figure out how to assign the variables to the array.
int [] Weapon_Count = new int [11] ;
for ( int i=0; i<11; i=i+1)
{
Weapon_Count [i] = ??? ;}
I hope this does make sense..
Please let me explain how to use a C#-array.
This creates an unitialized integer-array with 5 elements:
int[] a1= new int[5];
Assigning values 9,8,7,6 and 5:
(Please note that only indexes from 0 to 4 can be used. Index 5 is not valid.)
a1[0]=9;
a1[1]=8;
a1[2]=7;
a1[3]=6;
a1[4]=5;
The same can also achieved with just one line:
int[] a1= new int[] {9,8,7,6,5};
This might help you.
// Declaring the array
int[] Weapon_Count;
// Initializing the array with a size of 11
Weapon_Count = new int[11];
// Adding values to the array
for (int i = 0; i < Weapon_Count.Length; i++)
{
Weapon_Count[i] = i + 100;
}
// Printing the values in the array
for (int i = 0; i < Weapon_Count.Length; i++)
{
Console.WriteLine(Weapon_Count[i]);
}
// Same thing with a list
// Daclare and initializing the List of integers
List<int> weapon_list = new List<int>();
// Adding some values
weapon_list.Add(1);
weapon_list.Add(2);
weapon_list.Add(3);
weapon_list.Add(4);
weapon_list.Add(5);
// Printing weapin_list's values
for (int i = 0; i < weapon_list.Count; i++)
{
Console.WriteLine(weapon_list[i]);
}
// This is just for the console to wait when you are in debug mode.
Console.ReadKey();
Dont forget to include the using statment if you want to use lists (in short hand - dynamic arrays that can change in size.)
using System.Collections.Generic;
The easiest way to do this, assuming there is a finite list of variables to check, would be to throw them into a temporary array and call either Max() or Min() from the System.Linq namespace.
int maxCount = new int[] { Weapon_Count1, Weapon_Count2, Weapon_Count3, Weapon_Count4, Weapon_Count5, Weapon_Count6, Weapon_Count7, Weapon_Count8, Weapon_Count9 }.Max(); // or .Min()
EDIT
If you still want to get those variables into an array, I would recommend using a System.Collections.Generic.List which has a dynamic size and helper methods such as .Add() to simplify things. Lists can also be used with Linq functions similar to the first part of my answer. See Dot Net Perls for some really good examples on different C# data types and functions.
EDIT 2
As #kblok says, you'll want to add using System.Linq; at the top of your file to gain access to the functions such as Max and Min. If you want to try using the List type, you'll need to add using System.Collections.Generic; as well. If you're in Visual Studio 2017 (maybe 2015 as well?) you can type out the data type and then hit Ctrl + . to get suggestions for namespaces that might contain that data type.
Before we start, you might edit your array to look like this:
int[] weapons = { Weapon_Count1, Weapon_Count2, Weapon_Count3, Weapon_Count4, Weapon_Count5, Weapon_Count6, Weapon_Count7, Weapon_Count8, Weapon_Count9 };
This means that you've created an array called weapons and it is holding integer values.
After you did this, lets find out which element in your array has value of number one.
To find which value has value "1" we must look at each element in array, and we might do that on few ways but I would like recommend foreach or for loop, in this case I will choose foreach loop.
foreach(var item in weapons)
{
if (item == 1)
//Do something
}
This above means, loop throught all of my elements, and in case some of them is equal to number one please do something..
P.S
(I may advice to create one variable which will hold an element which has value '1' and when you find it in a loop assing that variable to that element, and later you can do whatever you want with that variable.. and if you think there will be more elements with value of number one and you need all of them, instead of variable I mentioned above you will create list or array to hold all of your elements and also you can do later with them whatever you want to.)
Thanks and if you are interested in this kind of solution, leave me a comment so let me help you till the end to solve this if you are still struggling.

Resetting a char array

I'm having a char array :
public static char[] boardposition = new char[9];
I want to reset the array , my written function for this is:
public static void Reset()
{
Array.Clear(boardposition,9, boardposition.Length);
}
When I call the Reset() I get an exception of type IndexOutOfRangeException.
I hope you guys can help me out.
You are passing 9 as starting index wich isn't a valid index for your array. Make the call like this Array.Clear(boardposition,0, boardposition.Length);
The method Array.Clear takes the following parameters:
Array array - the Array on which the Clear will be performed.
int index - the starting position from which to start clearing
int length - the number of elements which should be cleared.
A bit of test coding covereth a multitude of sins... including sins of misleading or unhelpful documentation.
In your case, the index caused the exception: the last valid position would be Length - 1.
As to the solution: if you intend to clear the entire array while retaining bot initial pointer and array size, the answer is:
Array.Clear(boardposition, 0, boardposition.Length );
If, however, you have no issues with changing the address of the Array, just assign it a new Array with same length; the end result would still be a zeroed Array of length 9:
boardposition = new char[9];
Edit: the best use scenario depends entirely on how boardposition is used later on in the program.
An IndexOutOfRangeException can be raised if the index is smaller than the lower bound of the array, the length is less than zero or if the sum of index and length is greater than the size of array.
In your case the sum of the index and length is (boardposition.Length+9) which exceeds the length of the array and therefore an exception is raised. You need to change your code to:
public static void Reset()
{
Array.Clear(boardposition,0, 9);
}

In c#, if I have already declared an array of length n, how can I add another element on to it, making it of length (n+1)? [duplicate]

This question already has answers here:
Most efficient way to append arrays in C#?
(11 answers)
Closed 8 years ago.
Background on the program: the heart of the program needs to track all other Forms or other elements of the program. To do this, I am using a Form array
What I am wanting to do is take my initially defined array containing 1 element, and increase the length of the array to add a new element whenever a new Form is launched.The trouble I've run into is that I can't find out how to do this without using a second array to store the old array, re-declaring the original array with array.length += 1, looping through to re-add the original content from the second array, then adding the new element. It's heavy and inconvenient since I need to use similar processes elsewhere.
The code I have, which works but is ugly, is this:
public class PCB
{
Form[] Runners;
public PCB()
{
Runners = new Form[1];
Runners[0] = new GUI;
.
.
.
.
.
void NewForm(Form app)
{
Form[] TEMP = Runners; //Create my new array equal to the first
Runners = new Form[Runners.Length + 1]; //re-create the old array, with an additional element
for (int k = 0; k < TEMP.Length; k++)
{
//add the original elements back to the original array
Runners[k] = TEMP[k];
}
Runners[TEMP.Length] = App; //add the final element to the array
I hate having to use the loop-structure, as I feel that it can be done cleaner. what I'm looking for is a function similar to the ListBox.Items.Add([[ITEM]]), but for an array.
Does such a function exist, or do I need to continue with my ugly loops?
Use a list instead:
List<Form> Runners = new List<Form>();
...
Runners.Add(app);
If you for some odd reason absolutely must use an array, then Array.Resize is what you're looking for, but a list is much better.
I believe what you're looking for is a List. A List already does this for you under the hood in .NET. You can do this:
List<Form> Runners;
Runners = new List<Form>();
Now when you add to the list you can do:
Runners.Add(new MyForm());
When you want to remove from the list you can do:
Runners.Remove(MyForm);
Just use a List<Form> list instead of arrays, which can be accessed just like an array and you can dynamically add other elements (list.Add(new Form(...))).
It is much more performant than an array and it has other features that can simplify your coding.
One way is to use Array.Resize
P.S. !!! be sure that the references to your array won't be changed.
Here is an example:
using System;
class aaa
{
static void Main()
{
string[] array = new string[10];
Array.Resize(ref array, 20);
}
}

Categories