PHP - pick random value from array? - php

How is it possible to pick a random value with PHP from an Array?
Example:
$trees = [
"appletree" => [
"id" => "12378",
"age" => [15],
"height" => [6]
],
"bananatree" => [
"id" => "344343453",
"age" => [16],
"height" => [30]
],
"peachtree" => [
"id" => "34534543",
"age" => [35],
"height" => [4]
];
How would I access one of the id's randomly?
I tried using
$tree_id = array_rand($trees['id']);
echo $tree_id;
echo "\r\n";
but I'm slowly hitting a wall of understanding.

array_rand() returns a random array key. So give it the $trees array to get a tree name, then use that to index the array and access its id property.
$random_tree = array_rand($trees);
echo $trees[$random_tree]['id'];

maybe this function I created can help:
<?php
$trees = [
"appletree" => [
"id" => "123",
"age" => [15],
"height" => [6]
],
"bananatree" => [
"id" => "456",
"age" => [16],
"height" => [30]
],
"peachtree" => [
"id" => "789",
"age" => [35],
"height" => [4]
] // <- you were missing this bracket
];
function pickRand($array){
// Create Temp array
$temparray = [];
// Iterate through all ID's and put them into out temp array
foreach($array as $a) $temparray[] = $a['id'];
// Get a random number out of the number of ID's we have
$rand = rand(0, count($temparray) - 1);
// Return Result
return $temparray[$rand];
}
// Use Function
echo pickRand($trees);
Live Demo: http://sandbox.onlinephpfunctions.com/code/e71dc6b07c3ec93051c69adc66b28aafe555a104

Related

PHP - Elegant way of removing values from Associative Arrays based on a key value duplication [duplicate]

This question already has answers here:
Filter/Remove rows where column value is found more than once in a multidimensional array
(4 answers)
Closed 10 months ago.
I have the following Associative Array below, and I wish to remove from the $filtered_results or $results the duplicated values based on the nid (number_id) field.
The solution I came up with, was to do a foreach loop, populate the new array with the key unique value that I wish and then return the array_values of that new array.
Is there a more elegant solution to tackle this problem ?
The order is irrelevant ( Replacing or keeping the current value);
Solution 1: Replacing the current value for the next.
$filtered_results = [];
foreach ($results as $k => $v) {
$filtered_results[ $v['nid'] ] = $v ;
}
return array_values ( $filtered_results ) ;
Solution 2: Keeping the first value found.
$filtered_results = [];
foreach ($results as $k => $v) {
if ( isset( $filtered_results[ $v['nid'] ] )) {
continue;
}
$filtered_results[ $v['nid'] ] = $v ;
}
Associative Array
$results = [
[
"date" => "2019-03-09",
"name" => "NameOne",
"phone" => "56784678",
"nid" => 1,
],
[
"date" => "2019-03-09",
"name" => "NameTwo",
"phone" => "123123123",
"nid" => 2,
],
[
"date" => "2019-03-09",
"name" => "NameThree",
"phone" => "6784568",
"nid" => 3,
],
[
"date" => "2019-03-09",
"name" => "NameFour",
"phone" => "90909090",
"nid" => 2,
],
[
"date" => "2019-03-09",
"name" => "NameFive",
"phone" => "3456356",
"nid" => 1,
],
];
Filtered Results
$filtered_results = [
[
"date" => "2019-03-09",
"name" => "NameThree",
"phone" => "6784568",
"nid" => 3,
],
[
"date" => "2019-03-09",
"name" => "NameFour",
"phone" => "90909090",
"nid" => 2,
],
[
"date" => "2019-03-09",
"name" => "NameFive",
"phone" => "3456356",
"nid" => 1,
],
]
Since is a duplicated question, the best solution I have found is :
array_values(array_column($results,NULL,'nid'))
Demo : https://onlinephp.io/c/fe78a
return array_intersect_key($results, array_unique(array_column($results, 'nid')));
use this :
$filtered_results = array_combine(array_column($results, 'nid'), $results);

How I can explode all string fields in Collection using Laravel

I have an array with fields
[
"house" => "30|30|30",
"street" => "first|second|third",
...
]
I want to get array
[
[
"house" => "30",
"street" => "first",
...
],
[
"house" => "30",
"street" => "second",
...
],
[
"house" => "30",
"street" => "third",
...
]
]
I know how I can solve this using PHP and loop, but maybe this problem has more beautiful solution
use zip
$data = [
"house" => "30|30|30",
"street" => "first|second|third",
];
$house = collect(explode('|',$data['house']));
$street = collect(explode('|',$data['street']));
$out = $house->zip($street);
$out->toarray();
Here's something I managed to do with tinker.
$original = [
"house" => "30|30|30",
"street" => "first|second|third",
];
$new = []; // technically not needed. data_set will instantiate the variable if it doesn't exist.
foreach ($original as $field => $values) {
foreach (explode('|', $values) as $index => $value) {
data_set($new, "$index.$field", $value);
}
}
/* dump($new)
[
[
"house" => "30",
"street" => "first",
],
[
"house" => "30",
"street" => "second",
],
[
"house" => "30",
"street" => "third",
],
]
*/
I tried using collections, but the main problem is the original array's length is not equal to the resulting array's length, so map operations don't really work. I suppose you can still use each though.
$new = []; // Since $new is used inside a Closure, it must be declared.
collect([
"house" => "30|30|30",
"street" => "first|second|third",
...
])
->map(fn($i) => collect(explode('|', $i))
->each(function ($values, $field) use (&$new) {
$values->each(function ($value, $index) use ($field, &$new) {
data_set($new, "$index.$field", $value);
});
});
$array = ["house" => "30|30|30","street" => "first |second| third"];
foreach($array as $key=> $values){
$explodeval = explode('|',$values);
for($i=0; $i<count($explodeval); $i++){
$newarray[$i][$key]= $explodeval[$i];
}
}
output:
Array
(
[0] => Array
(
[house] => 30
[street] => first
)
[1] => Array
(
[house] => 30
[street] => second
)
[2] => Array
(
[house] => 30
[street] => third
)
)

Extract "path" from array

I'm working on documenting an API, so I am parsing example XML/JSOn output and need to find all the named keys to add definitions. So, I have an array like this:
$array = [
"user" => [
"name" => "John",
"email" => "email#email.com",
"products" => [
0 => "product A",
1 => "product B"
],
"files" => [
"logo" => "/path/logo.jpg",
"profile" => "/path/profile.jpg"
]
],
"offer" => [
0 => "My offer"
]
];
And I want to extract all the keys from the array, no matter its depth, and get an output akin to:
$keys = [
0 => ["user"],
1 => ["user", "name"],
2 => ["user", "email"],
3 => ["user", "products"],
4 => ["user", "files"],
5 => ["user", "files", "logo"],
6 => ["user", "files", "profile"],
7 => ["offer"]
];
Note that keys that are numeric are ignored, only named keys are included in the hierarchy. I have googled and tried to find something that does this, but I've come up blank. I have tried some function chaining but I just can't wrap my head around the loops and returns correctly. Any help is appreciated!
Ok, with help of #0stone0 I was directed to a Stackoverflow answer that led me right, this is the end function:
function definitionTree(array $array): array{
$tree = function($siblings, $path) use (&$tree) {
$result = [];
foreach ($siblings as $key => $val) {
$currentPath = is_numeric($key) ? $path : array_merge($path, [$key]);
if (is_array($val)) {
if (!is_numeric($key)) $result[] = join(' / ', $currentPath);
$result = array_merge($result, $tree($val, $currentPath));
} else {
$result[] = join(' / ', $currentPath);
}
}
return $result;
};
$paths = $tree($array, []);
return array_unique($paths);
}
Which returns the following:
Array
(
[0] => user
[1] => user / name
[2] => user / email
[3] => user / products
[6] => user / files
[7] => user / files / logo
[8] => user / files / profile
[9] => offer
)

PHP get value from armultidimensional array based on array with keys [duplicate]

This question already has answers here:
How to access and manipulate multi-dimensional array by key names / path?
(10 answers)
Closed 2 years ago.
I'm trying to get reach a point in a dynamicly generated multidimensional array based on a array with keys.
Basicly I have the following array:
$arr = [
"something" => [
'something_else' => [
"another_thing" => "boo"
]
],
"something2" => [
'something_elseghf' => [
"another_thingfg" => [
"hi" => "bye"
]
]
],
"info" => [
'something_else2' => [
"another_thingh" => "boo"
]
],
];
Now I want to set a value in the array based on the keys in a different array:
$keyArr = ["something2", 'something_elseghf' "another_thingfg", "hi"];
So the above array means that I need to set the hi key to some value. How can I reach that part of the array with these random keys, note that the length of $keyArr is dynamic aswell. So I can't reach it with:
$arr[$keyArr[0]][$keyArr[1]][$keyArr[2]][$keyArr[3]] =
Hope anyone has an idea on how to solve this!
Try this approach:
$arr = [
"something" => [
'something_else' => [
"another_thing" => "boo"
]
],
"something2" => [
'something_elseghf' => [
"another_thingfg" => [
"hi" => "bye"
]
]
],
"info" => [
'something_else2' => [
"another_thingh" => "boo"
]
],
];
$keyArr = ["something2", 'something_elseghf', "another_thingfg", "hi"];
$cursor = $arr;
foreach ($keyArr as $key) {
$cursor = $cursor[$key];
}
echo $cursor;
Will echo
bye
UPDATE:
If you want to change a value within multi-dimentional array, then use a recursive function, like this:
function changeValue($array, $path, $value) {
if (empty($path)) {
return $value;
}
$key = array_shift($path);
$array[$key] = changeValue($array[$key], $path, $value);
return $array;
}
$arr = [
"something" => [
'something_else' => [
"another_thing" => "boo"
]
],
"something2" => [
'something_elseghf' => [
"another_thingfg" => [
"hi" => "bye"
]
]
],
"info" => [
'something_else2' => [
"another_thingh" => "boo"
]
],
];
$keyArr = ["something2", 'something_elseghf', "another_thingfg", "hi"];
$changedArray = changeValue($arr, $keyArr, 'New value!');
print_r($changedArray);
Will output
Array
(
[something] => Array
(
[something_else] => Array
(
[another_thing] => boo
)
)
[something2] => Array
(
[something_elseghf] => Array
(
[another_thingfg] => Array
(
[hi] => New value!
)
)
)
[info] => Array
(
[something_else2] => Array
(
[another_thingh] => boo
)
)
)

Elasticsearch partial bulk update

I have 6k of data to update in ElasticSearch. And I have to use PHP.
I search in the documentation and I have found this, Bulk Indexing but this is not keeping the previous data.
I have structure:
[
{
'name': 'Jonatahn',
'age' : 21
}
]
My code snippet to update:
$params =[
"index" => "customer",
"type" => "doc",
"body" => [
[
"index" => [
"_index" => "customer",
"_type" => "doc",
"_id" => "09310451939"
]
],
[
"name" => "Jonathan"
]
]
];
$client->bulk($params);
When I send ['name' => 'Jonathan'] I expect the name will be updated and keep the age, but the age gets deleted.
Sure, I still can update data-by-data but this will take a long time, is there any better way to do that?
My error was to using "index", but the correct way to do what I want, was "update".
The final code is:
$params =[
"index" => "customer",
"type" => "doc",
"body" => [
[
"update" => [
// ^^^^^^ Here I change from index to update
"_index" => "customer",
"_type" => "doc",
"_id" => "09310451939"
]
],
[
"doc" => [
"name" => "Jonathan"
]
]
]
];
$client->bulk($params);
Using the code above, my data keep previous data and just update the data I passing in params.
Response:
Array
(
[took] => 7
[timed_out] =>
[_shards] => Array
(
[total] => 5
[successful] => 5
[skipped] => 0
[failed] => 0
)
[hits] => Array
(
[total] => 1
[max_score] => 1
[hits] => Array
(
[0] => Array
(
[_index] => customer
[_type] => doc
[_id] => 09310451939
[_score] => 1
[_source] => Array
(
[name] => Jonathan
[age] => 23
)
)
)
)
)
As per docs, Bulk API possible actions are index, create, delete and update. update expects that the partial doc, upsert and script and its options are specified on the next line.
POST _bulk
{ "update" : {"_id" : "1", "_type" : "_doc", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
Here is my final code.
<?php
require_once('../elasticsearch.php');
//initialize elasticsearch
$params = array();
$params['index'] = $elastcsearch_index;
$params['type'] = $elastcsearch_type;
///////////////////////////////////////////////////
//update seeders n leechers in elasticsearch
//get updated records
$get_updated_records = mysqli_query($conn, "SELECT content_id, seeders, leechers FROM content WHERE is_updated = '1' order by seeders DESC") ;
//create blank array
$results = array();
while($row = mysqli_fetch_assoc($get_updated_records)){
//put all results in array
$results[] = $row;
}
//from https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/_indexing_documents.html
$params = ['body' => []];
for($i = 0; $i < count($results); $i++) {
$params["body"][]= [
"update" => [
"_index" => $elastcsearch_index,
"_type" => $elastcsearch_type,
"_id" => $results[$i]['content_id']
]
];
$params["body"][]= [
"doc" => [
"seeders" => intval($results[$i]['seeders']) ,
"leechers" => intval($results[$i]['leechers']) ,
]
];
// Every 1000 documents stop and send the bulk request
if ($i % 1000 == 0) {
$responses = $elasticsearch->bulk($params);
// erase the old bulk request
$params = ['body' => []];
// unset the bulk response when you are done to save memory
unset($responses);
}
}
// Send the last batch if it exists
if (!empty($params['body'])) {
$responses = $elasticsearch->bulk($params);
}
$batch_elastics is array of result
i just unset this two value from row each time....
because I don't need this value in insert or update
unset($batch_row['type']);
unset($batch_row['diamonds_id']);
code start from here...
if(count($batch_elastics)){
// echo 'hi';die;
$params = array();
$params = ['body' => []];
$i=1;
foreach($batch_elastics as $batch_row){
$type=$batch_row['type'];
$id=$batch_row['diamonds_id'];
unset($batch_row['type']);
unset($batch_row['diamonds_id']);
if($type=="create"){
$params["body"][]= [
"create" => [
"_index" => 'diamonds',
"_id" => $id,
]
];
$params["body"][]= $batch_row;
if ($i % 1000 == 0) {
$responses = $client->bulk($params);
$params = ['body' => []];
unset($responses);
}
}
$i=$i+1;
}
// Send the last batch if it exists
if (!empty($params['body'])) {
$responses = $client->bulk($params);
}
$params = array();
$params = ['body' => []];
$i=1;
foreach($batch_elastics as $batch_row){
$type=$batch_row['type'];
$id=$batch_row['diamonds_id'];
unset($batch_row['type']);
unset($batch_row['diamonds_id']);
if($type=="update"){
$params["body"][]= [
"update" => [
"_index" => 'diamonds',
"_id" => $id,
]
];
$params["body"][]= [
"doc"=>$batch_row
];
if ($i % 1000 == 0) {
$responses = $client->bulk($params);
$params = ['body' => []];
unset($responses);
}
}
$i=$i+1;
}
// Send the last batch if it exists
if (!empty($params['body'])) {
$responses = $client->bulk($params);
}
}

Categories