Dlist: using stableLinearRemove in a foreach loop - d

I've written the following code but it doesn't give the correct result (for instance if you enter [-1,-1], it returns [-1,-1,-1].
import std.stdio, std.range, std.container, std.algorithm;
DList!T strandSort(T)(DList!T list) {
static DList!T merge(DList!T left, DList!T right) {
DList!T res;
while (!left.empty && !right.empty) {
if (left.front <= right.front) {
res.insertBack(left.front);
left.removeFront();
} else {
res.insertBack(right.front);
right.removeFront();
}
}
res.insertBack(left[]);
res.insertBack(right[]);
return res;
}
DList!T result, sorted;
while (!list.empty) {
sorted.clear();
sorted.insertBack(list.front);
list.removeFront();
foreach (item; list) {
if (sorted.back <= item) {
sorted.insertBack(item);
list.stableLinearRemove(list[].find(item).take(1)));
}
}
result = merge(sorted, result);
}
return result;
}
void main() {
auto lst = DList!int([-1,-1]);
foreach (e; strandSort(lst))
writef("%d ", e);
}
Sometimes, the stableLinearRemove doesn't remove the item from the list. The question is, is it a bug in my code, or in Phobos?
See also the discusion on Rosettacode.org
Edit: I suspect it's caused by removeFront. It doesn't set the prev node pointer of the second node to null when the first node is removed. When the item to be removed from the list by linearRemove happens to be the first node, it won't be removed. The remove function checks "before" and "after" nodes and the "before" is still set. If I write it like this, it does work:
if (sorted.back <= item) {
sorted.insertBack(item);
if (list.front == item)
list.removeFront();
else
list.stableLinearRemove(list[].find(item).take(1)));
}

I don't think it's a bug in Phobos, but rather a gotcha. You shouldn't rely on linearRemove to remove an element if it might be the first in the list. Check for that first and use removeFront. Is also more efficient.
In the case above, a better solution would be to copy the list:
DList!T result, sorted, leftover;
while (!list.empty) {
leftover.clear();
sorted.clear();
sorted.insertBack(list.front);
list.removeFront();
foreach (item; list) {
if (sorted.back <= item)
sorted.insertBack(item);
else
leftover.insertBack(item);
}
result = merge(sorted, result);
list = leftover;
}

You are right, it is definitely a bug in removeFront.
Though I might point out that removing iterated elements via foreach is not going to be efficient even if it is supposed to be valid. you need a handle to the range. consider:
auto rng = list[];
while(!rng.empty) {
auto item = rng.front;
if(sorted.back <= item) {
sorted.insertBack(item);
auto rng2 = rng.save();
rng.popFront();
list.stableLinearRemove(rng2.take(1)); // O(1) removal!
}else{
rng.popFront();
}
}
Ah, well. Above probably doesn't work in light of the bug.

Related

list.remove_if() crashing the program

I'm working on a game and I'm trying to add collectables. I'm trying to remove the object from the list after the player has collided with it, but it ends up crashing and says:
Unhandled exception thrown: read access violation.
__that was 0xDDDDDDE9.
It says this on the for loop statement, but I think it has to do with the remove_if() function.
Here is my code:
for (sf::RectangleShape rect : world1.level1.brainFrag) {
collides = milo.sprite.getGlobalBounds().intersects(rect.getGlobalBounds());
if (collides == true) {
world1.level1.brainFrag.remove_if([rect](const sf::RectangleShape val) {
if (rect.getPosition() == val.getPosition()) {
return true;
}
else {
return false ;
}
});
brainFrag -= 1;
collides = false;
}
}
if (brainFrag == 0) {
milo.x = oldPos.x;
milo.y = oldPos.y;
brainFrag = -1;
}
I don't understand your approach, you loop the rects, then when you find the one you want to remove, you search for it again through list<T>::remove_if.
I think that you forgot about the fact that you can use iterators in addition to a range-based loop:
for (auto it = brainFrag.begin(); it != brainFrag.end(); /* do nothing */)
{
bool collides = ...;
if (collides)
it = world1.level1.brainFrag.erase(it);
else
++it;
}
This allows you to remove the elements while iterating the collection because erase will take care of returning a valid iterator to the element next to the one you removed.
Or even better you could move everything up directly:
brainFrag.remove_if([&milo] (const auto& rect) {
return milo.sprite.getGlobalBounds().intersects(rect.getGlobalBounds())
}
A side note: there's no need to use an if statement to return a boolean condition, so you don't need
if (a.getPosition() == b.getPosition()
return true;
else
return false;
You can simply
return a.getPosition() == b.getPosition();

How to protect app against read access violation while accessing to pointer's value?

I've created some chain-like structure, where one object has pointers to the next and previous object of a chain. The code below loops through entire chain, looks for value specified in arguments and removes matching element (if exists).
void List::removeElementByValue(int value)
{
ListMember* nextElem = this->firstValue;
while (nextElem) {
if (nextElem == NULL || nextElem == nullptr) {
break;
}
if (nextElem->value == value) {
if (nextElem->prevValue)
(nextElem->prevValue)->nextValue = nextElem->nextValue;
if (nextElem->nextValue)
(nextElem->nextValue)->prevValue = nextElem->prevValue;
delete nextElem;
this->count--;
return;
}
nextElem = nextElem->prevValue;
}
}
The problem is: I'm getting this error when I'm trying to remove non-existent value from chain.
Exception thrown: read access violation. nextElem was 0xCDCDCDCD.
Function should do nothing in that case. It happens at this line:
if (nextElem->value == value) {
As you see, I've used multiple ways to check if nextElem is correct, but I'm still getting this error. Any ways I can prevent that?
if (nextElem == NULL || nextElem == nullptr)
This will always be false when while (nextElem) is true.
nextElem = nextElem->prevValue;
This needs to use nextValue instead of prevValue.
But, most importantly, you are not updating this->firstValue if the value is found in the first element of the list, so you end up deleting the firstValue and leave it pointing at invalid memory.
Try this instead:
void List::removeElementByValue(int value)
{
ListMember* elem = this->firstValue;
while (elem) {
if (elem->value == value) {
if (elem->prevValue)
elem->prevValue->nextValue = elem->nextValue;
if (elem->nextValue)
elem->nextValue->prevValue = elem->prevValue;
// ADD THIS!!!
if (elem == this->firstValue)
this->firstValue = elem->nextValue;
delete elem;
this->count--;
return;
}
elem = elem->nextValue; // NOT prevValue!
}
}
A better solution is to not implement a linked list manually in the first place. Use the standard std::list container instead, let it do all of the hard hard for you.
#include <list>
class List
{
private:
std::list<int> values;
...
};
...
#include <algorithm>
void List::removeElementByValue(int value)
{
auto iter = std::find(values.begin(), values.end(), value);
if (iter != values.end())
values.erase(iter);
}

What's the best way to change the size of a list in Dart?

I have a list with oldLength items.
I want it to have newLength items.
If newLength < oldLength, I just want to cut the extra items.
If newLength > oldLength, I want to fill it with nulls.
I wrote this:
List<T> cutList<T>(List<T> oldList, int newLength) {
return new List.generate(newLength, (index) {
if (index < oldList.length) return oldList[index];
else return null;
});
}
Is there a better way, in terms of simplicity? And in terms of efficiency?
If it's a growable list and you don't mind mutating it:
List<T?> cutList<T>(List<T?> oldList, int newLength) {
oldList.length = newLength;
return oldList;
}
Notice that after Dart introduced Null Safety, you can only grow a list like this if its element type is nullable (because otherwise it can't assign null to the new element positions). Since you ask to grow with null values, that should be the case.
The declaration of cutList here ensures that the list type is nullable.
If you want to create a new list, then you still need to know that T is nullable (otherwise you can't create a larger list):
List<T?> cutList<T>(List<T?> oldList, int newLength) {
return List<T?>.filled(newLength, null)
..setRange(0, min(newLength, oldList.length), oldList);
}
(where min is imported from dart:math).
For a more modern-Dart approach, I'd probably go with:
List<T?> cutList<T>(List<T?> oldList, int newLength) {
return <T?>[...oldList.take(newLength),
for (var i = oldList.length; i < newLength; i++) null];
There are so many ways. Anything that only copies each element once is good.
Same as Above but It's an extension so you can use it on any List anytime you want
Without Math Library
extension CutList<T> on List<T?> {
List<T?> cutList(List<T?> oldList, int newLength) {
return <T?>[
...oldList.take(newLength),
for (var i = oldList.length; i < newLength; i++) null
];
}
}
With Math
import 'dart:math';
extension CutList<T> on List<T?> {
List<T?> cutList(List<T?> oldList, int newLength) {
return List<T?>.filled(newLength, null)
..setRange(0, min(newLength, oldList.length), oldList);
}
}

Remove Duplicates from sorted list not passing all testcases

This is a question on leetcode. For some reason my code only works for 7/164 test cases. i would like to know why my algorithm is not efficient.
what is a solution to this? what is wrong with my code?
here is link to the problem
https://leetcode.com/problems/remove-duplicates-from-sorted-list/description/
edit: i have taken suggestions and edited code but my algorithm is still not passing, i am getting a time limit exceed error. is the algorithm efficient?
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode* current = head;
ListNode* nex;
while(current!=NULL){
nex=current->next;
if (nex==NULL)
break;
if(current->val==nex->val)
current->next=nex->next;
if (current->next==NULL)
break;
current==current->next;
if(current->next==NULL)
break;
}
return current;
}
};
nex is not initialized. You try to compare it with NULL before it is initialized.
You remove duplicates of the neighbor pairs only. It is OK for sorted lists.
You get into memory leaks.
The final two if are odd.
I think you return from the function not what is expected.
Used == where = should be used.
Your should not change current after current->next changed.
while (current && (nex = current->next)){
if (current->val == nex->val) {
current->next = nex->next;
delete nex;
} else {
current = current->next;
}
}
return head;
Remove Duplicates from Sorted List (JavaScript) -> try this one
let deleteDuplicates = (head) => {
let inArray = []
let check = head.reduce((a, c) => {
if(a[c]) a[c] = ++a[c];
else a[c] = 1;
return a
},{})
for (var i in check) {
if (check[i] == 1) inArray.push(Number(i))
}
return inArray;
}
let output = deleteDuplicates([3,7,4,4,2])
console.log(output)

Why Removing item from list in this way is impossible?

I have a problem that as i try to remove item from any list in following way i am unable to do that ... why is that so the error is "use of unassigned local variable" where is it is assigned as shown below:
public void RemoveFrmList(int ProdId)
{
int _index;
foreach (Products item in BoughtItems)
{
if (item.ProductID == ProdId)
{
_index = BoughtItems.IndexOf(item);
}
}
BoughtItems.RemoveAt(_index);
}
what can be done to remove this error?
the code inside the if statement does not necessarily occur. Initialize _index to -1 or some "not found" indicating value and the error should go away.
What is BoughtItems ? If it's List<T> just use RemoveAll
public void RemoveFrmList(int ProdId)
{
BoughtItems.RemoveAll( item => item.ProductID == ProdId );
}
Slightly offtopic but why is RemoveFrmLis missing the o? It just hurts readability. Use the full word.
_index is unassigned until you go in the loop. But if BoughtItems has no Product items, you will have a unnassigned variable _index. Or maybe you will never get an item with item.ProductID == ProdID.
So in other words:
int _index;
foreach (Products item in BoughtItems)
{
//Code here is not executed during runtime for reasons stated above.
}
BoughtItems.RemoveAt(_index); //error here because _index was not assigned!
To fix it, you could do something like
int _index = -1;
foreach (...)
{
//...
}
if (_index != -1){
BoughtItems.RemoveAt(_index);
}
else
{
//handle case if needed
}