- Home /
Need some help looping through an array or list
Hi Unity,
I am stumped on a script I am trying to write, hoping you can come through.
Basically I have an array full of cubes with a a transform of course. I need to loop through this array and find any cubes that have a matching position.x or position.y. Then I need to count how many of of the cubes match in that axis.
The other problem is I need to do this in the update function because cubes will be added continuously up to a point.
I am pulling my hair out over this one!!
// Update is called once per frame
void Update ()
{
//Add all cube "lines" into an array
lines = GameObject.FindGameObjectsWithTag("Line");
//loop through array
for(int cnt = 0; cnt < lines.Length; cnt++)
{
//store the current position.x of the index??
tempPosX = lines[cnt].transform.position.x;
//if there is more than one cube..
if(cnt >= 1)
{
//and if this index matches the transform of the one of previous ones..?? I dont really know
//where I am going at this point..
if(tempPosX == lines[cnt].transform.position.x)
{
//We found a matching line cube on the x axis.
//Yay.. cubeCountX++? I dont know..
}
}
}
}
I tried something like the above but just cant figure out where to go from here..
If you are wondering what I am trying to make with this, its essentially a line drawn using cubes that are instantiated. I am trying to find the lenghth of the line and therefore be able to canculate square feet. (I am trying to make an app that you can calculate square feet by drawing an outline of a room).
Thanks a million!!
Answer by hoy_smallfry · Mar 01, 2013 at 01:26 AM
Iterating through so many elements in an array is a computationally exhaustive procedure. Think about the scenario here: you have to check every object with every other object.
If there's only 2 objects, there's only 1 comparison. If there are 3 objects, its 2 comparisons. With 4 objects, 6 comparisons. With 10, it's 45; with 11, 55; with 12, 66
Just 25 objects will raise it to 300 comparisons! This is referred to as the handshake problem in mathamatics. The number grows at a high rate, and those comparisons can give your CPU too much to do if the number is too high.
Thankfully, we can leverage memory against computational time.
So, you're trying to figure out which objects share the same axis value, right? Imagine that you can group GameObjects you come across into groups labeled by the axis value.
In C#, the perfect container for such a task is System.Collections.Generic.Dictionary
. Just like an array associates data with an integer index value, a dictionary can associate data with any key, like so:
// create a container that associates a string with an int
Dictionary<string, int> map = new Dictionary<string, int>();
map.Add("Bob", 1);
Debug.Log(map["Bob"]) // prints out 1 to the log
map["Bob"] = 5; // makes the element at "Bob" equal to 5
With dictionaries, you can associate any data type as the key
// create a container that associates a float with an int
Dictionary<float, int> map = new Dictionary<float, int>();
map.Add(3.14f, 1);
Debug.Log(map[3.14f]) // prints out 1 to the log
map[3.14f] = 5; // makes the element at 3.14f equal to 5
So, if you make a dictionary where the data is a list of GameObjects, we have a way of grouping GameObjects by float values.
Dictionary<float, List<GameObject> > xAxisMap = new Dictionary<float, List<GameObject> >();
You can then loop through your array, and place each one in the list that matches the X-axis value:
var lines = GameObject.FindGameObjectsWithTag("Line");
//loop through array
for(int cnt = 0; cnt < lines.Length; cnt++)
{
var x = tempPosX = lines[cnt].transform.position.x;
/* tries to find the value at x. if it was found, saves the value to
* 'group' and returns true. if not found, returns false. */
List<GameObject> group = null;
var wasFound = xAxisMap.TryGetValue(x, out group);
// if it was NOT found, then...
if (!wasFound)
{
// create a new group
group = new List<GameObject>();
// add the list to the dictionary at x.
xAxisMap.Add(x, group);
}
// now that we have the group, we add our gameObject to it
group.Add(lines[cnt]);
}
Doing it this way, we've now sorted all the lines that are on the same X value into groups. We only have to loop through the lines
once. A much better alternative to checking each object against each other object.
To get the x values all your objects are on:
foreach (float x in xAxisMap.Keys())
{
// do something with this x value!
}
To iterate through your groups:
foreach (List<GameObjects> group in xAxisMap.Values())
{
// do something with this group!
}
To get the x values and the groups:
foreach (var pair in xAxisMap)
{
// do something with this x value!
Debug.Log("Key: " + pair.Key);
// do something with this group!
List<GameObject> group = pair.Value;
}
Hope that helps!
That was one hell of an answer! Thanks! I have been wanting to start using dictionaries but wasnt quite sure where to start. This really helps me see how easy they can be to use, and how useful as well. Thanks much!!!!
fixed the definition for xAxis$$anonymous$$ap. it got stripped out probably because the submission throught it was an HT$$anonymous$$L tag or something
No problem, I was able to figure out what you meant. I am trying this now and will report back with results.
Can you tell me a bit more about what this does? I think I get the rest of it: List group = null;
(hmm doesnt want to display right list of GameObjects = null basically)
And where does wasFound become true exactly?
Never $$anonymous$$d I figured out where wasFOund becomes true. Ya lines 9 and 10 are a bit over my head, but I will read up on that code and try and understand it.
Answer by madmike6537 · Mar 03, 2013 at 04:42 AM
Here is what I ended up with for anyone interested out there. I realize it wasnt really necessary to put everything in a function, but I was trying to fix something and then I ended up just leaving it that way.
public class SquareFootage : MonoBehaviour
{
//array to hold all the line cubes
GameObject[] lines;
private float lastLineCount = 0;
public Dictionary<float, List<GameObject> > xAxisMap = new Dictionary<float, List<GameObject>>();
// Update is called once per frame
void Update ()
{
lines = GameObject.FindGameObjectsWithTag("Line");
if(lines.Length > lastLineCount)
{
print ("new line added");
BuildLineGroups();
lastLineCount = lines.Length;
}
}
void BuildLineGroups()
{
//loop through array of lines
for(int cnt = 0; cnt < lines.Length; cnt++)
{
print ("Looping through lines");
var x = lines[cnt].transform.position.x;
//Check to see if there is already an entry for x
//if there is, then it returns true otherwise its false
List<GameObject> myList;
bool wasFound = xAxisMap.TryGetValue(x, out myList);
if(wasFound)
{
print("matching group found for value " + x);
//check if this is a line that was already put into a group
//we do this by checking the "key" for the entry that it matches and we check to see if there is a matching transform.position in that entry
for(int i = 0; i<myList.Count; i++)
{
//if the position of this line matches that of any in the listed with key "X" then get outta here..
if(myList[i].transform.position == lines[cnt].transform.position)
{
print ("existing line found that matches this position, no line will be added");
return;
}
else
{
print ("line added to existing group" + x);
//otherwise, add this specific cube "line" to that group.
xAxisMap[x].Add(lines[cnt]);
}
}
}
//if no group with this position was found..
if(!wasFound)
{
print ("new group created: " + x);
//add to list as entry x(a float)
xAxisMap.Add(x, new List<GameObject>());
xAxisMap[x].Add(lines[cnt]);
}
}
}
void OnGUI()
{
foreach(KeyValuePair<float, List<GameObject>> line in xAxisMap)
{
Debug.Log(line.Key + "=" + line.Value.Count);
if(line.Value.Count > 1)
{
GUI.TextArea(new Rect(0,0,100,50), line.Value.Count.ToString());
}
}
}
}
But it still has some issues. It always thinks my line is in the same spot as another. Not sure if you can compare Vector 3's like I did or not, maybe I will post this in a new question.
On the contrary, I believe programmers should use functions whenever they can.
Your answer
Follow this Question
Related Questions
A node in a childnode? 1 Answer
How do i convert this code snippet to a list? 1 Answer
How to store gameobjects with specific scripts in a list ? 1 Answer
[C#]Inventory script help. 3 Answers
UnityScript for unique simpleJSON lists 0 Answers