JSON is object instead of array, if array_diff returns assoc array on Collection->toArray() - laravel

My issue is in my json I am expecting an array, but am getting an object.
Details:
I have an array of numbers:
$numbers = [1];
I select from relationship, the "drawn numbers":
$drawnNumbers = Ball::whereIn('number', $numbers)->where('game_id', $card->game->id)->get()->map(function($ball) {
return $ball->number;
})->toArray();
I do a ->toArray() here. I want to find the numbers in $numbers that do not occur in $drawnNumbers. I do so like this:
$numbersNotYetDrawn = array_diff($numbers, $drawnNumbers);
My method then return $numbersNotYetDrawn (my headers accept is application/json).
So now the issue. When $drawnNumbers is an empty array, then the printed json is a regular array like this:
[
1
]
However if the relationship returns $drawnNumbers to be an array with numbers, then json is printed as an object:
{
"0" => 1
}
Does anyone know why this is? Anyway to ensure that json is array?
Edit:
Here is my actual data:
$drawnNumbers = Ball::whereIn('number', $numbers)->where('game_id', $card->game->id)->get()->map(function($ball) {
return $ball->number;
})->toArray();
$undrawnNumbers = array_diff($numbers, $drawnNumbers);
// $undrawnNumbers = array_values(array_diff($numbers, $drawnNumbers)); // temp fix

Replace
$numbersNotYetDrawn = array_diff($numbers, $drawnNumbers);
with
$numbersNotYetDrawn = array_values(array_diff($numbers, $drawnNumbers));
to make sure element keys are reset and array is treated as a simple list and serialized to a JSON list - instead of being treated as an associative array and serialized to a JSON object.

I recently had this same problem and wondered the same thing.
I solved it by adding "array_values", but I was wondering how to reproduce it.
I found it that it is reproduced when array_diff removes an element from the array that isn't the last element. So:
>>> $x
=> [
1,
2,
3,
4,
5,
]
>>> array_diff($x, [5]);
=> [
1,
2,
3,
4,
]
>>> array_diff($x, [1]);
=> [
1 => 2,
2 => 3,
3 => 4,
4 => 5,
]

Related

Laravel: Access Rules::in variable items

How to access the items listed in an Illuminate\Validation\Rules\In variable ?
use Illuminate\Validation\Rules\In;
$foo = Rule::in('a', 'b');
$foo->toString() // error
The only way I found to show it is:
>>> dump($foo)
Illuminate\Validation\Rules\In^ {#3512
#rule: "in"
#values: array:2 [
0 => "a"
1 => "b"
]
}
you can convert that Illuminate\Validation\Rules\In to collection then take the result array:
$foo = Rule::in('a', 'b');
$values = collect($foo)->values()[1];
to get the string Representation from it:
$stringRepresentation=$foo->__toString();

Rxjs GroupBy, Reduce in order to Pivot on ID

I'm looking for a bit of help understanding this example taken from the rxjs docs.
Observable.of<Obj>({id: 1, name: 'aze1'},
{id: 2, name: 'sf2'},
{id: 2, name: 'dg2'},
{id: 1, name: 'erg1'},
{id: 1, name: 'df1'},
{id: 2, name: 'sfqfb2'},
{id: 3, name: 'qfs1'},
{id: 2, name: 'qsgqsfg2'}
)
.groupBy(p => p.id, p => p.name)
.flatMap( (group$) => group$.reduce((acc, cur) => [...acc, cur], ["" + group$.key]))
.map(arr => ({'id': parseInt(arr[0]), 'values': arr.slice(1)}))
.subscribe(p => console.log(p));
So the aim here is to group all the items by id and produce an object with a single ID and a values property which includes all the emitted names with matching IDs.
The second parameter to the groupBy operator identifies the return value. Effectively filtering the emitted object's properties down to the name. I suppose the same thing could be achieved by mapping the observable beforehand. Is it possible to pass more than one value to the return value parameter?
The line I am finding very confusing is this one:
.flatMap( (group$) => group$.reduce((acc, cur) => [...acc, cur], ["" + group$.key]))
I get that we now have three grouped observables (for the 3 ids) that are effectively arrays of emitted objects. With each grouped observable the aim of this code is to reduce it an array, where the first entry in the array is the key and subsequent entries in the array are the names.
But why is the reduce function initialized with ["" + group$.key], rather than just [group$.key]?
And why is this three dot notation [...acc, cur] used when returning the reduced array on each iteration?
But why is the reduce function initialized with ["" + group$.key], rather than just [group$.key]?
The clue to answer this question is in the .map() function a bit further down in the code.
.map(arr => ({'id': parseInt(arr[0]), 'values': arr.slice(1)}))
^^^^^^^^
Note the use parseInt. Without the "" + in the flatMap this simply wouldn't compile since you'd be passing a number type to a function that expects a string. Remove the parseInt and just use arr[0] and you can remove "" + as well.
And why is this three dot notation [...acc, cur] used when returning
the reduced array on each iteration?
The spread operator here is used to add to the array without mutating the array. But what does it do? It will copy the original array, take all the existing elements out of the array, and deposit the elements in the new array. In simpler words, take all elements in acc, copy them to a new array with cur in the end. Here is a nice blog post about object mutation in general.

Laravel eloquent gives array of numbers, instead of integers

I'm trying to return id's as a string and pass them via api (using for select later)
Using Laravel resouces:
public function toArray($request)
{
return [
'speciality' => $this->specialities()->pluck('speciality_id')
];
}
and it returns an array of numbers, like:
[1, 3, 5, 7]
How can I convert them within eloquent query and return like a string?
["1", "3", "5", "7"]
You could loop through the array, cast it to string and add to new array as it is only required for this specific case.
$a = [1, 3, 5, 7];
$b = array();
foreach($a as $as)
$b[] = (string)$as;
return $b;
Or better use array_map() -
$a = array_map(function($value){
return (string) $value;
}, $a);
It's a bit awful, but if have no choice then
cast it to string
protected $casts=[
'speciality_id'=>'string'
];

Rxjs distinct and arrays of numbers

I can't explain to myself this
const something = new Rx.BehaviorSubject([1,2,4,4])
.distinct()
.do((s) => console.log(s))
.map(list => list.length)
.filter(length => length >=2)
.subscribe(total => console.log('total:', total));
this is what I get as output
[1, 2, 4, 4]
"total:"
4
I get confused because reviewing the docs on distinct I thought it would work for numbers. My use case is a data table widget sends me events and this array tracks which row they clicked and I want to detect once a double click occurred.
updated code
const something = new Rx.BehaviorSubject([]);
something.next([1]);
console.log(something.getValue());
something.next(something.getValue().concat(2));
something.next(something.getValue().concat(3));
something.next(something.getValue().concat(4));
something.next(something.getValue().concat(4));
something
.distinct()
.subscribe(val => console.log('value:', val));
output
"value:"
[1, 2, 3, 4, 4]
You're sending a value that happens to be an array. You would see the operation of distinct if you did
const something = new Rx.BehaviorSubject([]);
something .distinct() .subscribe(val => console.log('value:', val));
something.next(1); // --> value: 1
something.next(2); // --> value: 2
something.next(1); // no output (because of distinct)
something.next(3); // --> value: 3

Ruby Nested Hash with Composite Unique Keys

Given a comma separated CSV file in the following format:
Day,User,Requests,Page Views,Browse Time,Total Bytes,Bytes Received,Bytes Sent
"Jul 25, 2012","abc123",3,0,0,13855,3287,10568
"Jul 25, 2012","abc230",1,0,0,1192,331,861
"Jul 25, 2012",,7,0,0,10990,2288,8702
"Jul 24, 2012","123456",3,0,0,3530,770,2760
"Jul 24, 2012","abc123",19,1,30,85879,67791,18088
I wanted to drop the entire dataset (1000 users over 30 days = 30,000 records) into a hash such that Key 1 may be a duplicate key, key 2 may be a duplicate key, but Key 1 & 2 will be unique together.
Example using line 1 above:
report_hash = "Jul 25, 2012" => "abc123" => {"PageRequest" => 3, "PageViews" => 0, "BrowseTime" => 0, "TotalBytes" => 13855, "BytesReceived" => 3287, "BytesSent" => 10568}
def hashing(file)
#read the CSV file into an Array
report_arr = CSV.read(file)
#drop the header row
report_arr.drop(1)
#Create an empty hash to save the data to
report_hash = {}
#for each row in the array,
#if the first element in the array is not a key in the hash, make one
report_arr.each{|row|
if report_hash[row[0]].nil?
report_hash[row[0]] = Hash.new
#If the key exists, does the 2nd key exist? if not, make one
elsif report_hash[row[0]][row[1]].nil?
report_hash[row[0]][row[1]] = Hash.new
end
#throw all the other data into the 2-key hash
report_hash[row[0]][row[1]] = {"PageRequest" => row[2].to_i, "PageViews" => row[3].to_i, "BrowseTime" => row[4].to_i, "TotalBytes" => row[5].to_i, "BytesReceived" => row[6].to_i, "BytesSent" => row[7].to_i}
}
return report_hash
end
I spent several hours learning hashes and associated content to get this far, but feel like there is a much more efficient method to do this. Any suggestions on the proper/more efficient way of creating a nested hash with the first two keys being the first two elements of the array such that they create a "composite" unique key?
You could use the array [day, user] as the hash key.
report_hash = {
["Jul 25, 2012","abc123"] =>
{
"PageRequest" => 3,
"PageViews" => 0,
"BrowseTime" => 0,
"TotalBytes" => 13855,
"BytesReceived" => 3287,
"BytesSent" => 10568
}
}
You just have to make sure the date and user always appear the same. If your date (for example) appears in a different format sometimes, you'll have to normalize it before using it to read or write the hash.
A similar way would be to convert the day + user into a string, using some delimiter between them. But you have to be more careful that the delimiter doesn't appear in the day or the user.
EDIT:
Also make sure you don't modify the hash keys. Using arrays as keys makes this a very easy mistake to make. If you really wanted to, you could modify a copy using dup, like this:
new_key = report_hash.keys.first.dup
new_key[1] = 'another_user'

Resources