I'm working on "Move Zeroes" of leetcode with scala. https://leetcode.com/problems/move-zeroes/description/
Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements. You must do this in-place without making a copy of the array.
I have a solution which works well in IntelliJ but get the same Array with input while executing in Leetcode, also I'm not sure whether it is done in-place... Something wrong with my code ?
Thanks
def moveZeroes(nums: Array[Int]): Array[Int] = {
val lengthOrig = nums.length
val lengthFilfter = nums.filter(_ != 0).length
var numsWithoutZero = nums.filter(_ != 0)
var numZero = lengthOrig - lengthFilfter
while (numZero > 0){
numsWithoutZero = numsWithoutZero :+ 0
numZero = numZero - 1
}
numsWithoutZero
}
And one more thing: the template code given by leetcode returns Unit type but mine returns Array.
def moveZeroes(nums: Array[Int]): Unit = {
}
While I agree with #ayush, Leetcode is explicitly asking you to use mutable states. You need to update the input array so that it contains the changes. Also, they ask you to do that in a minimal number of operations.
So, while it is not idiomatic Scala code, I suggest you a solution allong these lines:
def moveZeroes(nums: Array[Int]): Unit = {
var i = 0
var lastNonZeroFoundAt = 0
while (i < nums.size) {
if(nums(i) != 0) {
nums(lastNonZeroFoundAt) = nums(i)
lastNonZeroFoundAt += 1
}
i += 1
i = lastNonZeroFoundAt
while(i < nums.size) {
nums(i) = 0
i += 1
}
}
As this is non-idomatic Scala, writing such code is not encouraged and thus, a little bit difficult to read. The C++ version that is shown in the solutions may actually be easier to read and help you to understand my code above:
void moveZeroes(vector<int>& nums) {
int lastNonZeroFoundAt = 0;
// If the current element is not 0, then we need to
// append it just in front of last non 0 element we found.
for (int i = 0; i < nums.size(); i++) {
if (nums[i] != 0) {
nums[lastNonZeroFoundAt++] = nums[i];
}
}
// After we have finished processing new elements,
// all the non-zero elements are already at beginning of array.
// We just need to fill remaining array with 0's.
for (int i = lastNonZeroFoundAt; i < nums.size(); i++) {
nums[i] = 0;
}
}
Your answer gives TLE (Time Limit Exceeded) error in LeetCode..I do not know what the criteria is for that to occur..However i see a lot of things in your code that are not perfect .
Pure functional programming discourages use of any mutable state and rather focuses on using val for everything.
I would try it this way --
def moveZeroes(nums: Array[Int]): Array[Int] = {
val nonZero = nums.filter(_ != 0)
val numZero = nums.length - nonZero.length
val zeros = Array.fill(numZero){0}
nonZero ++ zeros
}
P.S - This also gives TLE in Leetcode but still i guess in terms of being functional its better..Open for reviews though.
first question ever here...
I am coding a simple 3-card poker hand evaluator and am having problems finding/extracting multiple "straights" (sequential series of values) from an array of values.
I need to extract and return EVERY straight the array possibly has. Here's an example:
(assume array is first sorted numerically incrementing)
myArray = [1h,2h,3c,3h,4c]
Possible three-value sequences are:
[1h,2h,3c]
[1h,2h,3h]
[2h,3c,4c]
[2h,3h,4c]
Here is my original code to find sequences of 3, where the array contains card objects with .value and .suit. For simplicity in this question I just put "2h" etc here:
private var _pokerHand = [1h,2h,3c,3h,4c];
private function getAllStraights(): Array
{
var foundStraights:Array = new Array();
for (var i: int = 0; i < (_handLength - 2); i++)
{
if ((_pokerHand[i].value - _pokerHand[i + 1].value) == 1 && (_pokerHand[i + 1].value - _pokerHand[i + 2].value) == 1)
{
trace("found a straight!");
foundStraights.push(new Array(_pokerHand[i], _pokerHand[i + 1], _pokerHand[i + 2]));
}
}
return foundStraights;
}
but it of course fails when there are value duplicates (like the 3's above). I cannot discard duplicates because they could be of different suits. I need every possible straight as in the example above. This allows me to run the straights through a "Flush" function to find "straight flush".
What array iteration technique am I missing?
This is an interesting problem. Given the popularity of poker games (and Flash) I'm sure this has been solved many times before, but I couldn't find an example online. Here's how I would approach it:
Look at it like a path finding problem.
Begin with every card in the hand as the start of a possible path (straight).
While there are possible straights:
Remove one from the list.
Find all the next valid steps, (could be none, or up to 4 following cards with the same value), and for each next valid step:
If it reaches the goal (completes a straight) add it to a list of found straights.
Otherwise add the possible straight with the next step back to the stack.
This seems to do what you want (Card object has .value as int):
private function getAllStraights(cards:Vector.<Card>, straightLength:uint = 3):Vector.<Vector.<Card>> {
var foundStraights:Vector.<Vector.<Card>> = new <Vector.<Card>>[];
var possibleStraights:Vector.<Vector.<Card>> = new <Vector.<Card>>[];
for each (var startingCard:Card in cards) {
possibleStraights.push(new <Card>[startingCard]);
}
while (possibleStraights.length) {
var possibleStraight:Vector.<Card> = possibleStraights.shift();
var lastCard:Card = possibleStraight[possibleStraight.length - 1];
var possibleNextCards:Vector.<Card> = new <Card>[];
for (var i:int = cards.indexOf(lastCard) + 1; i < cards.length; i++) {
var nextCard:Card = cards[i];
if (nextCard.value == lastCard.value)
continue;
if (nextCard.value == lastCard.value + 1)
possibleNextCards.push(nextCard);
else
break;
}
for each (var possibleNextCard:Card in possibleNextCards) {
var possibleNextStraight:Vector.<Card> = possibleStraight.slice().concat(new <Card>[possibleNextCard]);
if (possibleNextStraight.length == straightLength)
foundStraights.push(possibleNextStraight);
else
possibleStraights.push(possibleNextStraight);
}
}
return foundStraights;
}
Given [1♥,2♥,3♣,3♥,4♣] you get: [1♥,2♥,3♣], [1♥,2♥,3♥], [2♥,3♣,4♣], [2♥,3♥,4♣]
It gets really interesting when you have a lot of duplicates, like [1♥,1♣,1♦,1♠,2♥,2♣,3♦,3♠,4♣,4♦,4♥]. This gives you:
[1♥,2♥,3♦], [1♥,2♥,3♠], [1♥,2♣,3♦], [1♥,2♣,3♠], [1♣,2♥,3♦], [1♣,2♥,3♠], [1♣,2♣,3♦], [1♣,2♣,3♠], [1♦,2♥,3♦], [1♦,2♥,3♠], [1♦,2♣,3♦], [1♦,2♣,3♠], [1♠,2♥,3♦], [1♠,2♥,3♠], [1♠,2♣,3♦], [1♠,2♣,3♠], [2♥,3♦,4♣], [2♥,3♦,4♦], [2♥,3♦,4♥], [2♥,3♠,4♣], [2♥,3♠,4♦], [2♥,3♠,4♥], [2♣,3♦,4♣], [2♣,3♦,4♦], [2♣,3♦,4♥], [2♣,3♠,4♣], [2♣,3♠,4♦], [2♣,3♠,4♥]
I haven't checked this thoroughly but it looks right at a glance.
I'm trying to create a function that will work for any array-like object in Flash but I'm really struggling to find a way to let the compiler know what I'm doing. I need to use functions like indexOf on the argument, but unless it is cast to the correct data type the compiler doesn't know that method is available. It's frustrating because Vector and Array share pretty much the same interface but there isn't an Interface to reflect that!
At the moment I've got this:
private function deleteFirst(tV:* , tVal:*):void {
trace(tV)
var tIndex:int
if (tV is Array) {
var tArray:Array = tV as Array
tIndex = tArray.indexOf(tVal)
if (tIndex >= 0) tArray.splice(tIndex, 1)
} else if (tV is Vector.<*>) {
var tVObj:Vector.<*> = tV as Vector.<*>
tIndex = tVObj.indexOf(tVal)
if (tIndex >= 0) tVObj.splice(tIndex, 1)
} else if (tV is Vector.<Number>) {
var tVNum:Vector.<Number> = tV as Vector.<Number>
tIndex = tVNum.indexOf(tVal)
if (tIndex >= 0) tVNum.splice(tIndex, 1)
} else if (tV is Vector.<int>) {
var tVInt:Vector.<int> = tV as Vector.<int>
tIndex = tVInt.indexOf(tVal)
if (tIndex >= 0) tVInt.splice(tIndex, 1)
} else if (tV is Vector.<uint>) {
var tVUInt:Vector.<uint> = tV as Vector.<uint>
tIndex = tVUInt.indexOf(tVal)
if (tIndex >= 0) tVUInt.splice(tIndex, 1)
}
trace(tV)
}
It kind of works but it's not exactly elegant! I'm wondering if there's a trick I'm missing. Ideally I'd do this by extending the base class, but I don't think that's possible with Vector.
Thanks
I would be very careful about mixing and matching Vectors and Arrays. The biggest difference between them is that Arrays are sparse, and Vectors are dense.
That said, here is your very compact generic removal function that will work on ANY "set" class that has indexOf and splice...
function deleteFirst( set:Object, elem:Object ) : Boolean
{
if ( ("indexOf" in set) && ("splice" in set) )
{
var idx:int = set.indexOf( elem );
if ( idx >= 0 )
{
set.splice( idx, 1 );
return true;
}
}
return false;
}
You can test the code with this code
var arr:Array = [ 1, 2, 3, 4, 5 ];
var vec:Vector.<int> = new Vector.<int>();
vec.push( 1, 2, 3, 4, 5 );
deleteFirst( arr, 2 ); // will remove 2
deleteFirst( vec, 3 ); // will remove 3
deleteFirst( "aaa4", "4" ); // nothing, cuz String doesn't have splice
trace( arr );
trace( vec );
UPDATE - For #Arron only, I've made the below change. Note that getting exceptions is good. They are informative and help reveal issues with the code path.
function deleteFirst( set:Object, elem:Object ) : Boolean
{
var idx:int = set.indexOf( elem );
if ( idx >= 0 )
{
set.splice( idx, 1 );
return true;
}
return false;
}
There! Now it's even simpler. You get an exception that tells you what's wrong!
This is definitely a short-coming of AS3, I don't think there is any elegant solution.
However, one code simplification you can make:
Since the syntax for indexOf() and splice() is the same for both arrays and vectors, you don't need that big if/else ladder to cast every type. You can simply call indexOf() and splice() on the object without any casting. Of course, you don't get any code-hints in your IDE, but it will work the same as you currently have. Example:
function deleteFirst(arrayOrVector:* , searchValue:*):* {
if (arrayOrVector is Array || arrayOrVector is Vector.<*> || arrayOrVector is Vector.<Number> || arrayOrVector is Vector.<int> || arrayOrVector is Vector.<uint>) {
var index:int = arrayOrVector.indexOf(searchValue)
if (index >= 0)
arrayOrVector.splice(index, 1)
}else
throw new ArgumentError("Argument 'arrayOrVector' must be an array or a vector, but was type " + getQualifiedClassName(arrayOrVector));
return arrayOrVector;
}
You can even skip the whole if/else type check and it would still work, it would just make the code more confusing, and you would get a slightly more confusing error if you called the function with an argument other than array or vector (like "indexOf not found on type Sprite" if you passed a sprite object by accident).
Also it's worth mentioning that, while this doesn't help you with number base type vectors, with other vectors you can sort of use Vector.<*> as a generic vector reference. You can assign a reference using the Vector global function with wildcard (Vector.<*>(myVector)) and it will return a reference to the original vector instead of a new copy as it usually does. If you don't mind returning a copy of number based type vectors instead of always modifying the original vector, you can still take advantage of this to simplify your code:
function deleteFirst(arrayOrVector:* , searchValue:*):* {
if (arrayOrVector is Array) {
var array:Array = arrayOrVector;
var index:int = array.indexOf(searchValue)
if (index >= 0)
array.splice(index, 1)
return array;
}else if(arrayOrVector is Vector.<*> || arrayOrVector is Vector.<Number> || arrayOrVector is Vector.<int> || arrayOrVector is Vector.<uint>) {
var vector:Vector.<*> = Vector.<*>(arrayOrVector);
index = vector.indexOf(searchValue);
if (index >= 0)
vector.splice(index, 1);
return vector;
}
throw new ArgumentError("Argument 'arrayOrVector' must be an array or a vector, but was type " + getQualifiedClassName(arrayOrVector));
}
Okay so this is my code
var no:int = 0;
var elem:int = 0;
loadedData = myLoader.data.split(/\r\n|\n|\r/);
for (var i:int = 0; i < loadedData.length; i++)
{
if (loadedData[i] != '')
{
if (loadedData[i] != ',')
{
if(patterns[no] == undefined) patterns[no] = [];
trace(no);
trace(elem);
obstacleData[i] = loadedData[i].split(",");
trace(patterns[no]);
patterns[no][elem] = obstacleData[i][0];
patterns[no][elem + 1] = obstacleData[i][1];
elem += 2;
trace('Pattern' , no, ': ', patterns[no]);
}
else if (loadedData[i] == ',')
{
no += 1;
elem = 0;
patterns[no] = 0;
}
}
}
The problem is at this line
patterns[no][elem] = obstacleData[i][0];
I'm getting the error: [Fault] exception, information=ReferenceError: Error #1056: Cannot create property 0 on Number.
I've read around on this and multidimensional arrays just seem to be so much more complicated on AS3 compared to other languages where you just create a multidimensional array and it works.
I feel like I've done something really obvious wrong and will feel like an idiot upon someone telling me but I really need help on this one since I'm new to this whole AS3 way of creating multidimensional arrays.
Just in case the output for the code when run is as so:
0
0
Pattern 0 : 300,60
0
2
300,60
Pattern 0 : 300,60,350,90
1
0
0 <--- This might be the problem?
[Fault] exception, information=ReferenceError: Error #1056: Cannot create property 0 on Number.
Maybe the error is caused by the line
patterns[no] = 0;
I think you want to assign an empty array or maybe null and check for null later.
I'm trying to search a substring in an array of Strings. I'm using the following code (in Unity3):
var obstacles = ["Border", "Boundary", "BoundaryFlame"];
var frontAvailable = true;
var leftAvailable = true;
var rightAvailable = true;
var hitFront: RaycastHit;
if (Physics.Raycast(transform.position, transform.position + transform.forward, hitFront, 1.5)) {
Debug.Log("I hit this in front: ");
Debug.Log(hitFront.collider.gameObject.name);
for (var i = 0; i < obstacles.length; i++)
{
if (obstacles[i].IndexOf(hitFront.collider.gameObject.name) > -1)
{
Debug.Log("Hit in front!");
frontAvailable = false;
}
}
}
The problem is, the Debug.Log shows Boundary(Clone). I've included Boundary in the array obstacles. Shouldn't below code set frontAvailable to false? Or did I make a mistake here?
In addition to Kolink's answer, your if is looking for Boundary(clone) at the beginning of Boundary, rather than the other way around. I think you're looking for:
if (hitFront.collider.gameObject.name.IndexOf(obstacles[i]) >= 0)
I think you need indexOf, not IndexOf. Assuming you're talking about the native string function.
In addition, indexOf returns -1 if there is no match, 0 if the match is at the start, 1, 2, 3... for further positions. So you need > -1 instead of > 0