Queue move item back to the end - c#

I have a System.Collection.Generic.Queue<int> with following sample code
Queue<int> iq = new Queue<int>();
iq.Enqueue(1); // 1
iq.Enqueue(2); // 1 2
iq.Enqueue(3); // 1 2 3
//move 1 to the end of the line here
int i = iq.Dequeue(); // 2 3
I want to move the value (access by value) 1 back to the end of the line so that the result is 2 and 1 would be the last dequeueable value.
Any idea? Is there something like iq.MoveToLast(1) ?

If you want to Remove / Add item by its value, you can use List<T> instead of Queue<T>:
List<int> id = ...
int itemToMove = 2;
int index = id.IndexOf(itemToMove);
// If we have item found we should put it at the end
if (index >= 0) {
id.Add(id[index]);
id.RemoveAt(index);
}
If you have to use Queue<T> you can create a temporal List<T>:
Queue<int> iq = ...
int itemToMove = 2;
// Create temporal list
var list = iq.ToList();
// process items in it
int index = list.IndexOf(itemToMove);
if (index >= 0) {
list.Add(list[index]);
list.RemoveAt(index);
}
// enqueue items back into queue in the desired order
iq.Clear();
foreach (var item in list)
iq.Enqueue(item);
Finally, you can implement an extension method:
public static partial class QueueExtensions {
public static void MoveToLast<T>(this Queue<int> queue, T itemToMove) {
if (null == queue)
throw new ArgumentNullException(nameof(queue));
var list = queue.ToList();
int index = list.IndexOf(itemToMove);
if (index < 0)
return; // Nothing to do
list.Add(list[index]);
list.RemoveAt(index);
queue.Clear();
foreach (var item in list)
queue.Enqueue(item);
}
}
Then you can put
iq.MoveToLast(1);

Just try:
queue.Enqueue(queue.Dequeue());
You can't Remove elements from Queue by using methods other than Dequeue.

Here's an approach which just manipulates the queue:
public static void MoveElementToBack<T>(Queue<T> queue, T elementToMove)
{
T item = default;
bool found = false;
for (int i = 0, n = queue.Count; i < n; ++i)
{
var current = queue.Dequeue();
if (!found && current.Equals(elementToMove))
{
item = current;
found = true;
}
else
{
queue.Enqueue(current);
}
}
if (found)
queue.Enqueue(item);
}
This is always an O(N) operation, but it only makes one pass through the queue.

Related

C# Unity foreach loop exits early without break?

I'm trying to count items (int id) in a list. Doing it so:
int currentId = -1;
int count = 0;
foreach (var item in rawItemList) {
UnityEngine.Debug.LogFormat("Item {0}", item);
if (currentId != item) {
AddItem(currentId, count);
count = 0;
}
currentId = item;
count++;
UnityEngine.Debug.LogFormat("Count {0}", count);
}
And here's the AddItem function:
void AddItem(int itemId, int count) {
UnityEngine.Debug.LogFormat("Add item {0} count {1}", itemId, count);
if (count == 0) return;
items.Add(itemId);
counts.Add(count);
}
rawItemList, items and counts are all NativeList<int>.
There are 7 elements in rawItemList - {0, 0, 2, 2, 3, 4, 4}. Printing those before and after above loop works fine (prints all the elements).
The issue I'm having is that after second AddItem call, the foreach loop exits, not even printing the rest of elements in rawItemList. Maybe worth mentioning, this code happens in a constructor. Is there a bug in here I'm not seeing?
Console log:
Item 0
Add item -1 count 0
Count 1
Item 0
Count 2
Item 2
Add item 0 count 2
Count 1
// Loop exits here
EDIT:
Just checked with standard for loop. Works fine this way. What's wrong with foreach?
EDIT 2:
Inserting full code. The last item is added outside of the loop.
// public struct CountedItemList ...
public NativeList<int> items;
public NativeList<int> counts;
public CountedItemList(NativeList<int> rawItemList) {
items = new NativeList<int>(Allocator.Temp);
counts = new NativeList<int>(Allocator.Temp);
if (rawItemList.Length == 0) return;
rawItemList.Sort();
int currentId = -1;
int count = 0;
foreach (var item in rawItemList) {
UnityEngine.Debug.LogFormat("Item {0}", item);
if (currentId != item) {
AddItem(currentId, count);
count = 0;
}
currentId = item;
count++;
UnityEngine.Debug.LogFormat("Count {0}", count);
}
AddItem(currentId, count);
}
It's called like this from another script:
NativeList<int> rawItemList = new NativeList<int>(Allocator.Temp);
// Populate items
var cil = new CountedItemList(rawItemList);
rawItemList.Dispose();
EDIT 3:
In EDIT 1 I've replaced
foreach(var item in rawItemList) {
With
for(int i = 0; i < rawItemList.Length; i++ {
int item = rawItemList[i];
The rest of the code stayed the same, yet the behavior changed.
As said pure logic wise I can not reproduce this.
However, I implemented more or less exactly what you have in Unity like this
public class Test : MonoBehaviour
{
private CountedItemList cil;
private void Start()
{
NativeList<int> rawItemList = new NativeList<int>(Allocator.Temp);
// Populate items
rawItemList.Add(0);
rawItemList.Add(0);
rawItemList.Add(2);
rawItemList.Add(2);
rawItemList.Add(2);
rawItemList.Add(3);
rawItemList.Add(3);
rawItemList.Add(4);
cil = new CountedItemList(rawItemList);
rawItemList.Dispose();
}
private void OnDestroy()
{
cil?.Dispose();
}
}
public class CountedItemList : IDisposable
{
public NativeList<int> items;
public NativeList<int> counts;
public CountedItemList(NativeList<int> rawItemList)
{
items = new NativeList<int>(Allocator.Temp);
counts = new NativeList<int>(Allocator.Temp);
if (rawItemList.Length == 0) return;
rawItemList.Sort();
var currentId = -1;
var count = 0;
//for(var i = 0; i < rawItemList.Length; i++)
//{
// var item = rawItemList[i];
foreach (var item in rawItemList)
{
UnityEngine.Debug.LogFormat("Item {0}", item);
if (currentId != item)
{
AddItem(currentId, count);
count = 0;
}
currentId = item;
count++;
UnityEngine.Debug.LogFormat("Count {0}", count);
}
AddItem(currentId, count);
}
void AddItem(int itemId, int count)
{
UnityEngine.Debug.LogFormat("Add item {0} count {1}", itemId, count);
if (count == 0) return;
items.Add(itemId);
counts.Add(count);
}
public void Dispose()
{
items.Dispose();
counts.Dispose();
}
}
Which results in a pretty not ignorable exception
ObjectDisposedException: The Unity.Collections.NativeList`1[System.Int32] has been deallocated, it is not allowed to access it
Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckReadAndThrowNoEarlyOut (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) (at <86acb61e0d2b4b36bc20af11093be9a5>:0)
Unity.Collections.NativeArray`1[T].CheckElementReadAccess (System.Int32 index) (at <86acb61e0d2b4b36bc20af11093be9a5>:0)
Unity.Collections.NativeArray`1[T].get_Item (System.Int32 index) (at <86acb61e0d2b4b36bc20af11093be9a5>:0)
Unity.Collections.NativeArray`1+Enumerator[T].get_Current () (at <86acb61e0d2b4b36bc20af11093be9a5>:0)
CountedItemList..ctor (Unity.Collections.NativeList`1[T] rawItemList) (at Assets/Scripts/ExamplePart.cs:24)
Test.Start () (at Assets/Scripts/Test.cs:24)
pointing to the line
foreach (var item in rawItemList)
I think the explanation is something like
The NativeList<int>.GetEnumerator used by foreach seems to be iterating asynchronously. You immediately do
var cil = new CountedItemList(rawItemList);
rawItemList.Dispose();
so the rawItemList.Dispose(); seems to get called before the iteration via foreach is finished.
On the other hand for uses no special enumerator but synchronous index accesses so here it is ensured hat the constructor is finished before the list is diposed.

Skip foreach X positions

I want skip my in foreach. For example:
foreach(Times t in timeList)
{
if(t.Time == 20)
{
timeList.Skip(3);
}
}
I want "jump" 3 positions in my list.. If, in my if block t.Id = 10 after skip I want get t.Id = 13
How about this? If you use a for loop then you can just step the index forward as needed:
for (var x = 0; x < timeList.Length; x++)
{
if (timeList[x].Time == 20)
{
// option 1
x += 2; // 'x++' in the for loop will +1,
// we are adding +2 more to make it 3?
// option 2
// x += 3; // just add 3!
}
}
You can't modify an enumerable in-flight, as it were, like you could the index of a for loop; you must account for it up front. Fortunately there are several way to do this.
Here's one:
foreach(Times t in timeList.Where(t => t.Time < 20 || t.Time > 22))
{
}
There's also the .Skip() option, but to use it you must break the list into two separate enumerables and then rejoin them:
var times1 = timeList.TakeWhile(t => t.Time != 20);
var times2 = timeList.SkipeWhile(t => t.Time != 20).Skip(3);
foreach(var t in times1.Concat(times2))
{
}
But that's not exactly efficient, as it requires iterating over the first part of the sequence twice (and won't work at all for Read Once -style sequences). To fix this, you can make a custom enumerator:
public static IEnumerable<T> SkipAt<T>(this IEnumerable<T> items, Predicate<T> SkipTrigger, int SkipCount)
{
bool triggered = false;
int SkipsRemaining = 0;
var e = items.GetEnumerator();
while (e.MoveNext())
{
if (!triggered && SkipTrigger(e.Current))
{
triggered = true;
SkipsRemaining = SkipCount;
}
if (triggered)
{
SkipsRemaining--;
if (SkipsRemaining == 0) triggered = false;
}
else
{
yield return e.Current;
}
}
}
Then you could use it like this:
foreach(Times t in timeList.SkipAt(t => t.Times == 20, 3))
{
}
But again: you still need to decide about this up front, rather than inside the loop body.
For fun, I felt like adding an overload that uses another predicate to tell the enumerator when to resume:
public static IEnumerable<T> SkipAt<T>(this IEnumerable<T> items, Predicate<T> SkipTrigger, Predicate<T> ResumeTrigger)
{
bool triggered = false;
var e = items.GetEnumerator();
while (e.MoveNext())
{
if (!triggered && SkipTrigger(e.Current))
{
triggered = true;
}
if (triggered)
{
if (ResumeTrigger(e.Current)) triggered = false;
}
else
{
yield return e.Current;
}
}
}
You can use continue with some simple variables.
int skipCount = 0;
bool skip = false;
foreach (var x in myList)
{
if (skipCount == 3)
{
skip = false;
skipCount = 0;
}
if (x.time == 20)
{
skip = true;
skipCount = 0;
}
if (skip)
{
skipCount++;
continue;
}
// here you do whatever you don't want to skip
}
Or if you can use a for-loop, increase the index like this:
for (int i = 0; i < times.Count)
{
if (times[i].time == 20)
{
i += 2; // 2 + 1 loop increment
continue;
}
// here you do whatever you don't want to skip
}

Function that returns a new list of all children with allocation VS function that returns a child of that list without allocation

I'm trying to work out a way to iterate through all the children (including children of children) of an object without creating garbage allocation.
The function I had before was a Recursive function that returned a list.
Now I have two functions one that returns a count and the other that gets the child at a certain index.
I feel like there might be a better way to iterate through all the children of an object
Here is a sample code comparing the recursive list and the recursive count + getAt(index)
public class MyClassWithChildren
{
private MyClassWithChildren[] m_Children;
//With allocation
public IReadOnlyList<MyClassWithChildren> GetAllChildren(bool includeThis = false)
{
var allChildren = new List<MyClassWithChildren>();
if (includeThis) {
allChildren.Add(this);
}
if (m_Children != null) {
for (int i = 0; i < m_Children.Length; i++) {
allChildren.AddRange(m_Children[i].GetAllChildren(true));
}
}
return allChildren;
}
//Without allocation combination of count and getAt(index)
public int GetAllChildrenCount(bool includeThis = false)
{
var count = 0;
if (includeThis) { count++; }
for (int i = 0; i < m_Children.Length; i++) {
count += 1 + m_Children[i].GetAllChildrenCount();
}
return count;
}
public MyClassWithChildren GetAllChildrenAt(int index, bool includeThis = false)
{
if (includeThis) {
if (index == 0) { return this;}
index--;
}
for (int i = 0; i < m_Children.Length; i++) {
if (index == 0) { return m_Children[i]; }
index--;
var newIndex = index - m_Children[i].GetAllChildrenCount(false);
if (newIndex < 0) { return m_Children[i].GetAllChildrenAt(index); }
index = newIndex;
}
return null;
}
}
Does anyone know of a better way to do this?
A simple use case for this would be to search if a certain object is a child of another.
Another would be to find all the children that have a certain property value.
Thank you for your time
Maybe this will is what you're looking for:
public IEnumerable<MyClassWithChildren> GetAllChildren()
{
var items = new Queue<MyClassWithChildren>();
items.Enqueue(this);
while (items.TryDequeue(out var result))
{
yield return result;
for (var i = 0; i < result.m_children.Length; ++i) // use for instead of foreach to avoid enumerator creation
{
items.Enqueue(result.m_children[i]);
}
}
}
This will evaluate the children of a returned value after the external loop has processed it and requests the next one. That means all children are lazy iterated. If your external loop will stop after the first element only this element has been enqueued to the result queue. There is no overhead for enumerators in m_children because this code uses a for-loop instead of a foreach-loop.
If you need the count of all Elements - just use linq: GetAllChildren().Count().

How can the anagram code be improved and made faster?

The program runs slowly when there are more than 10 characters, I would like to do it quickly. I do not understand how I can improve and ask for your help.
And still need to count and number those combinations that do not occur in their original positions, I think if I add this logic, then the program will work even longer, and this also requires your advice
P.S. sorry for my English)
private void btnGo_Click(object sender, EventArgs e)
{
this.Size = new Size(632, 430);
button1.Visible = true;
// Get the items.
string[] items = txtItems.Text.Split(' ');
// string[] items = txtItems.Text.ToString;
// Generate the permutations.
List<List<string>> results =
GeneratePermutations<string>(items.ToList());
// results.Where(x => !HasCharacterAtSamePositionAsInOriginal(items, x));
List<string> list = new List<string>();
// Display the results.
lstPermutations.Items.Clear();
foreach (List<string> combination in results.Where(x => !HasCharacterAtSamePositionAsInOriginal(items, x)))
{
if (checkBox1.Checked == true)
{
lstPermutations.Items.Add(string.Join("", combination.ToArray()));
}
else
{
lstPermutations.Items.Add(string.Join(" ", combination.ToArray()));
}
}
// Calculate the number of permutations.
long num_permutations = Factorial(items.Length);
txtNumPermutations.Text = num_permutations.ToString();
// Check the result.
// Debug.Assert(lstPermutations.Items.Count == num_permutations);
}
private List<List<T>> GeneratePermutations<T>(List<T> items)
{
// Make an array to hold the
// permutation we are building.
T[] current_permutation = new T[items.Count];
// Make an array to tell whether
// an item is in the current selection.
bool[] in_selection = new bool[items.Count];
// Make a result list.
List<List<T>> results = new List<List<T>>();
// Build the combinations recursively.
PermuteItems<T>(items, in_selection,
current_permutation, results, 0);
// Return the results.
return results;
}
// Recursively permute the items that are
// not yet in the current selection.
private void PermuteItems<T>(List<T> items, bool[] in_selection,
T[] current_permutation, List<List<T>> results, int next_position)
{
// See if all of the positions are filled.
if (next_position == items.Count)
{
// All of the positioned are filled.
// Save this permutation.
results.Add(current_permutation.ToList());
}
else
{
// Try options for the next position.
for (int i = 0; i < items.Count; i++)
{
if (!in_selection[i])
{
// Add this item to the current permutation.
in_selection[i] = true;
current_permutation[next_position] = items[i];
// Recursively fill the remaining positions.
PermuteItems<T>(items, in_selection,
current_permutation, results, next_position + 1);
// Remove the item from the current permutation.
in_selection[i] = false;
}
}
}
}
// Return n!
private long Factorial(long n)
{
long result = 1;
for (int i = 2; i <= n; i++) result *= i;
return result;
}
bool HasCharacterAtSamePositionAsInOriginal(string [] originalWord, List<string> anagram) //check the symbol occurs in its original location or not
{
for (var i = 0; i < originalWord.Length; i++)
{
if (originalWord[i].Equals(anagram[i]))
{
return true;
}
}
return false;
}

Removing elements of a collection that I am foreaching through

Here is some dummy code that illustrates what I want to do:
List<int> list1 = new List<int>();
//Code to fill the list
foreach(int number in list1)
{
if(number%5==0)
{
list1.Remove(number);
}
}
Assuming the test actually removes an int, it will throw an error. Is there a way of doing this in a foreach, or do I have to convert it to a for loop?
You can't remove items from a collection that you are iterating thru with a for each.
I would do this...
list1 = list1.Where(l => l % 5 != 0).ToList();
The RemoveAll() method comes closest to what you want, I think:
list1.RemoveAll(i => i%5 == 0);
Actually if you want to remove the list as you state in the O.P you could do:
List<int> list1 = new List<int>();
//Code to fill the list
for(var n = 0; n < list.Count; i++)
{
if (list[n] % 5 == 0)
{
list1.Remove(list[n--]);
}
}
Edited to Add
The reason why you can't change a list while in a for each loos is as follows:
[Serializable()]
public struct Enumerator : IEnumerator<T>, System.Collections.IEnumerator
{
private List<T> list;
private int index;
private int version;
private T current;
internal Enumerator(List<T> list) {
this.list = list;
index = 0;
version = list._version;
current = default(T);
}
public void Dispose() {
}
public bool MoveNext() {
List<T> localList = list;
if (version == localList._version && ((uint)index < (uint)localList._size))
{
current = localList._items[index];
index++;
return true;
}
return MoveNextRare();
}
private bool MoveNextRare()
{
if (version != list._version) {
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
index = list._size + 1;
current = default(T);
return false;
}
public T Current {
get {
return current;
}
}
Object System.Collections.IEnumerator.Current {
get {
if( index == 0 || index == list._size + 1) {
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);
}
return Current;
}
}
void System.Collections.IEnumerator.Reset() {
if (version != list._version) {
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
index = 0;
current = default(T);
}
}
As far as I know, a collection cannot be modified while in a foreach loop. You need to change it to a for loop. Another way you can accomplish that is using LINQ.
You can't do it in-situ using foreach, because it invalidates the enumerator.
Either take a copy of the list and iterate over that, or use a different type of loop such as a for() loop.
You cannot modify the collection your are enumerating through using foreach. What I often do is use a for loop and go backwards through the collection, thus you can safely remove items since the length won't be affected until you move to the previous item.

Categories

Resources