New programmer here. I'm trying to add a range of elements to a new list in C#. This is for a game I'm making in Unity. It's a game based on the old nokia Snake game, where each time the snake eats a fruit it gets longer. This information is stored in a list in my game. Now the thing is I'm trying to create a game element where at a certain point all the nodes from the snake (the tail basically) break away from the snake itself, and the snake has 3 elements remaining (the head, body, and a tail). I got it to work perfectly fine, except for the fact I can't get the range of nodes in the list to transfer to the newNode list for the life of me.
for (int i = 0; i < nodes.Count; i++)
{
if (nodes.Count > 3)
{
newNodes.Add(nodes[4]);
newNodes.Add(nodes[5]);
newNodes.Add(nodes[6]);
newNodes.AddRange(nodes[3], nodes.Count - 3);
nodes.RemoveRange(3, nodes.Count - 3);
}
When I run the game, the expected behavior works for the newNodes.Add (individual nodes). But what I would like is to see happen is something along the lines of newNodes.AddRange(nodes[3], nodes.Count - 3); But that doesn't work. How can I get it so it reads the nodes from 3 or 2 or whatever value to the total nodes in the list. I've been stuck on this for days! Really could use some help/input.
The code above is not complete, it's part of a coroutine actually that should get called after certain criteria has been met. It's just that I wonder if there's any way to do this?
Using the LINQ extension method Skip you can skip over the first part of a list and get the rest. As it is an extension method, you first need this near the top of your code file:
using System.Linq;
Then you can use this to add all but the first three items to the new list:
newNodes.AddRange(nodes.Skip(3));
Note: this doesn't change "nodes" in any way.
Bonus: if "nodes" contains 3 items or less, this will not fail (but of course add nothing to newNodes)
Try this :
newNodes.InsertRange(newNodes.Count - 1, nodes.GetRange(3, nodes.Count - 3));
nodes.RemoveRange(3, nodes.Count - 3);
If newNodes is empty, you need to make sure to pass 0 as index instead of
newNodes.Count - 1
As said, I'm a new programmer and have never used Stackoverflow. I'm truly overwhelmed by all the responses in such a short time, thank all for taking the time to read my question and trying to figure it out with me.
The code that seemed to work in my case was
newNodes.InsertRange(newNodes.Count, nodes.GetRange(3, nodes.Count - 3));
It basically captures all the nodes (snake bodies) in the list and releases them properly in a new list!
Again thanks!!
The problem is when you use
newNodes.AddRange(nodes[3], nodes.Count - 3);
you're only providing the single node at index 3. AddRange expects an IEnumerable, not a single object from a list. To get an IEnumerable you have to use the GetRange or LINQ methods that have already been posted by others.
Related
I have a single list with objects. Let's call it ItemList. Objects have properties such as Name, Code, ParentCode and so on. Some of these items have the same ParentCode and I need to compare the first element's ParentCode with the next one in some conditions. So I am using an if condition like this:
if (ItemList.First().ParentCode != ItemList.ElementAt(1).ParentCode)
However, sometimes this causes some issues because the ItemList can have single element inside it and it throws argument out of range or index out of range exception. To overcome this I changed the code to this:
if (ItemList.Count >= 2 && ItemList.First().ParentCode != ItemList.ElementAt(1).ParentCode)
Sometimes I need to run the same method when the ItemList have only one element or the first element does not have the equal ParentCode with the second element so I use this condition:
if (ItemList.Count == 1 || ItemList.Count >= 2 && ItemList.First().ParentCode != ItemList.ElementAt(1).ParentCode)
All of these seems counterintuitive thus I am open to suggestions on making to code more maintainable and readable. Thanks in advance!
A couple other Linq functions may help here, depending on the use-case. I'm not sure I fully understand why you'd only want to compare the first 2 elements though. What if it has 10 or 100 items? Only the first 2 matter? If it can only ever have 2 elements because of some other business logic, then consider creating a class that holds exactly 2 items, and put the "comparison/validation" logic inside that class. A constructor that accepts 2 parameters, first + second instance, should ensure validity of the wrapper class.
Either way... for a purely LINQ solution...
ItemList.GroupBy(x => x.ParentCode).Where(x => x.Count() > 1) ... will get you a list of "groups" that contain more than 1 duplicate ParentCode. Iterating that will provide you with a "Key" representing the ParentCode or whatever you group by.
ItemList.Skip(1).FirstOrDefault() ... will get you the second element, if it exists, otherwise it will be the default for whatever type is in the list
Is there any specific reason you have to use linq here? I feel like just referencing the objects directly is just as good of a solution.
if(ItemList.Count == 2)
{
if(ItemList[0].ParentCode != ItemList[1].ParentCode)
{
..do stuff..
}
}
Yes, the code isn't as flat, but this is extremely readable. If you need to compare the 0th value to more than just 1st value, checking that the list's length is greater than or equal to 2 and using a for loop will work just fine.
if(ItemList.Count >= 2)
{
for (var i = 1; i < ItemList.Count; i++)
{
if(ItemList[0].ParentCode != ItemList[i].ParentCode)
{
..do stuff..
}
}
}
Only suggesting a non-linq solution because you didn't mention that it had to be linq. This code is still extremely readable and has no difference in performance. Also, as you mentioned in your post, none of this code seems counterintuitive.
We have the Enqueue and Dequeue methods to work on a queue in C#.
But is there a way we can remove the last item in the queue? Dequeue actually removes the item from the top.
The entire purpose of a Queue is to walk the collection from top to bottom. If you want a collection type that allows removing from the back too (or any place in the collection), use another collection type, a List<T> for example.
Maybe you should consider using a Stack instead of a Queue.
Stack works similar to a queue but instead of the first in first out behaviour a stack is used when you need a last in first out solution for your objects
This is an expensive operation, so I only do this rarely. People here getting mad and not answering... all you do is just use a second Queue to move everything to:
// original queue must already be filled up
Queue<Waypoint> waypoints = new Queue<Waypoint>();
// fill it up...
Queue<Waypoint> temp = new Queue<Waypoint>();
while (waypoints.Count > 0) // stop one short of the end
{
temp.Enqueue(waypoints.Dequeue());
}
Waypoint wp = waypoints.Dequeue();
// get the last one and do what you desire to it...
// I modified mine and then added it back, this is not needed
temp.Enqueue(new Waypoint(wp.pos, (p.vectorPath[0] - wp.pos).normalized));
// necessary: you have waypoints empty now so you have to swap it for temp:
waypoints = temp;
Like Patrick stated the queue is meant to be first in first out. Think of it like a printer queue, the first page that goes to into the printer queue is the first to be printed out.
Look into using a List instead of an Array, I found lists a bit easier to manipulate with a bunch of extended methods that arrays do not have.
http://www.dotnetperls.com/list
Here is a link to how to remove the last item in a list which has a few different ways of accomplishing it.
How to remove the last element added into the List?
hope this helps!
I have to solve the rushhour problem using iterative deepening search, I'm generating new node for every move, everything works fine, except that it takes too much time to compute everything and the reason for this is that I'm generating duplicated nodes. Any ideas how to check for duplicates?
First I start at the root, then there is a method which checks every car whether is it possible to move it if yes, new node is created from the current node but the one car that has valid move replaced with new car that has new coordinates.
Problem is that the deeper the algorithm is the more duplicates moves there are.
I have tried to not to replace the car, but used the same collection as was used in root node but then the cars were moving only in one direction.
I think that I need to tie car collection somehow, but don't know how.
The code
Any ideas how to stop making duplicates?
Off topic: I'm new to C# (read several tutorial and then have been using for 2 days) so can you tell me what I'm doing wrong or what should I not do?
If you want to stick with iterative deepening, then the simplest solution may be to build a hash table. Then all you need to do with each new node is something like
NewNode = GenerateNextNode
if not InHashTable(NewNode) then
AddToHashTable(NewNode)
Process(NewNode)
Alternately, the number of possible positions (nodes) in RushHour is fairly small (assuming you are using the standard board dimensions) and it is possible to generate all possible (and impossible!) boards fairly easily. Then rather than iterative deepening you can start with the 'solution' state and work backwards (ticking off all possible 'parent' states) until you reach the start state. By working on the table of possible states you never generate duplicates, and by tagging each state once it is visited you never re-visit states.
Say I have a bunch of question fields and users can rearrange them and send to the server the new position and old position of the question(s) that have had their position altered and the server will then use this data to update all the effected questions position/number value in the database. As stated I am only sending back the new position and old position of the question(s) that have been moved and not of those effected before or after it etc. So that calculation will have to be done at the server.
So lets say I have questions numbered.
1 2 3 4 5 6 7 8
If I rearrange them as such
8 1 2 3 4 5 6 7
Then all values between the new position for (question 8), which is now 1 and old position (8) will need to be updated, with 1 - 7 getting a +1 and 8 being changed to 1. This is of course a simplified scenario, the questions can be rearranged to a much greater complexity where effected ranges will overlap and other ranges terminate within other ranges etc. So the required increments and decrements will be combined. Sounds like a fairly common scenario so if someone can put up an example, preferably in c# would be great.
Something along the lines of the answers above: Can you just add a 'position' property to the question object (independent of it's position in the list)? The user changes this property when they rearrange. Then you can just do a ListOfQuestions.OrderBy(q => q.Position)?
This just
This looks to me like you're trying to simply do random insertions and removals of a collection.
If that is the case, a Linked List is a good option for that. A linked list essentially has a head node(first node) and each node has a next attribute, which references another list.
that way, if you want to remove a node you can just make that node's parent node point to that node's child, and if you want to insert a node you can do the reverse.
c# has a built-in linked list class that you might want to check out
An alternative would be to:
1. Create your fixed size list/collection (Collection A)
2. Put the questions with modified positions on the new positions/index
3. Iterate through original question collection and placing the unmoved questions in the empty positions of the new collection (Collection A). Update question indexes based on their positions in the new collection.
Crude I know.
I have a situation that I am not quite sure where to start looking. I have been searching for the past four hours and I couldn't find anything that does what I am looking to do.
I have eight objects controlling individual lights. When an event occurs I generate an ID of it, store that value in the first available object, and start a method. I also store the ID in a list and match the object number to the index number of that list. What I would like to do is have those eight objects update and rotate depending if the matching item is removed from the list.
Example: There are five out of the eight objects active and I remove an item from the list indexed at 0. Object 0 is stopped then object 1 is moved to object 0 then 2 to 1, 3 to 2, etc.
So my question is what terms should I look up to help me accomplish that goal? I am relatively new to c# and with the results of my research today I just want to know what is the right question to ask.
If what I am looking to do is impossible just say so and I will come up with a more simple program on my end. Or if you have a solution to that situation I am all ears.
I think you're just describing a [stack data structure](https://en.wikipedia.org/wiki/Stack_(abstract_data_type). Check it out and see if it's what you're looking for.
A stack doesn't "rotate" objects, but when you remove the top item, the "index" of all the other items will decrement as you described. In your example, it seems like the list would eventually become empty (after 8 events) which is consistent with a stack - but it's not clear why one would call this rotation.
If a stack is what you're looking for, the BCL defines a generic Stack<T> that can do this. You add items to a stack with the Push() operation, which has the side effect of incrementing the index of all other items in the structure. The dual Pop operation removes the top item from the collection and decrements the index of the other items, as you described.