bit of a question here. Ive got an array that contains data which has been parsed from a website using all our favourite php functions such as array_map.
The array is current 3 sub arrays deep.
Here is the code I am using:
for ($tcid = 1; $tcid <= count($categories); $tcid++) {
$catHeader[$tcid] = $categories[$tcid][0];
$event[$i]['tickets'] = $categories;
unset($categories[$tcid][0]);
$categories[$tcid] = array_map('trim', $categories[$tcid]);
$categories[$tcid] = array_values($categories[$tcid]);
$ab = 0;
for ($b = 0; $b <= count($categories[$tcid]); $b++) {
if ($categories[$tcid][$b] == "" || !$categories[$tcid][$b] || $categories[$tcid][$b] == null) {
unset($categories[$tcid][$b]);
}
}
}
and the array looks something like....
[1] => Array (
[data] => Array ( ...
)
[tickets] => Array (
[1] => Array (
[0] => xxx
[1] => etc
[3] => etc2
)
[2] => (
[0] => Std1
[1] => 10 / 10
[2] => £20.00
[3] => £200.00
[4] => Std2
[5] => 100 / 100
[6] => £13.00
[7] => £1,300.00
[8] => Std3
[9] => 10 / 320
[10] => £15.00
[11] => £150.00
)
)
)
My question to you today, is how on earth do I split the array every 4 \n's or array keys as they're known and explode each 4 into a further sub array?
So that Std1, Std2, Std3 will be their own sub array with its associated data of the 2nd key of tickets, but also doing this for every sub array of tickets that has more than 1 set of data (a set of data being 4 array keys).
I've tried all sorts but can't get it to work.
See below of how I want it to look.
[1] => Array (
[data] => Array ( ...
)
[tickets] => Array (
[1] => Array (
[0] => xxx
[1] => etc
[3] => etc2
)
[2] => (
[0] => Array (
[0] => Std1
[1] => 10 / 10
[2] => £20.00
[3] => £200.00
)
[1] => Array (
[0] => Std2
[1] => 100 / 100
[2] => £13.00
[3] => £1,300.00
)
[2] => Array (
[0] => Std3
[1] => 10 / 320
[2] => £15.00
[3] => £150.00
)
)
)
)
Thanks
As noted in the comments, you'd be best off handling your array by-reference to modify it's original contents somewhere within your loops
Provided the array groupings you want to chunk are in groups of 4, you could array_chunk() it:
$array['tickets'][2] = array_chunk($array['tickets'][2], 4);
Related
I would like to switch from array 1 to array 2 according to the model below
I'm stuck on the implementation of item averages
the lessons, the number of notes and the order of the notes are random
Array 1
$tabAsso =
Array
(
[51] => Array
(
[id] => 51
[name] => JOHN
[studies] => Array
(
[0] => math
[1] => LV1
[2] => math
[3] => LV1
[4] => history
[5] => history
)
[notesC] => Array
(
[0] => 12
[1] => 18
[2] => 28
[3] => 45
[4] => 10
[5] => 18
)
[denumsC] => Array
(
[0] => 15
[1] => 60
[2] => 40
[3] => 75
[4] => 12
[5] => 45
)
)
[52] => Array
(
[id] => 52
[name] => PETER
[studies] => Array
(
[0] => sport
[1] => tech
[2] => sport
...
For example for the math average, you must read :
notesC:
sum (12 + 28)
denumC
sum (15 +40)
then average : (40/55) *20 = 14.5
I would like to reach this array 2
[51] => Array
(
[id] => 51
[name] => JOHN
[studies] => Array
(
[0] => math
[1] => LV1
[2] => history
)
[averages] => Array
(
[0] => 14.5
[1] => 9.3
[2] => 9.8
)
)
[52] => Array
(
[id] => 52
[name] => PETER
[studies] => Array
(
[0] => sport
[1] => tech
)
[averages] => Array
(
[0] => xx
[1] => xx
)
)
...
So far I have managed to do this ...
$tabAssoForBar = [];
foreach ($tabAsso as $id => $t) {
foreach ($t['studies'] as $k => $m) {
if (!array_key_exists($id, $tabAssoForBar)) {
$tabAssoForBar[$id] = [
'id' => $id,
'name' => $t['name'],
];
$tabAssoForBar[$id]['studies'] = [$m];
} else {
if (!in_array($m, $tabAssoForBar[$id]['studies'])) {
$tabAssoForBar[$id]['studies'][] = $m;
} else {
// nothing
}
}
}
};
I return studies with only 3 fields (math, LV1, history) but cannot create the averages field
Thanks for your help
You might use an approach to get all the indices from
"study" for a all the unique values, and get the values from "notesC" and "denumsC" for those corresponding indices.
Then per unique value for "study", first sum them separately for "notesC" and "denumsC" and then divide those results and multiply the outcome by 20 to fulfill this formula:
(40/55) *20 = 14.5
You can create the result array by using the current index as the index in the new array and the unique studies and averages to it.
For example
$tabAssoForBar = [];
foreach ($tabAsso as $id => $t) {
$uniqueStudies = array_unique($t['studies']);
$averages = [];
foreach ($uniqueStudies as $uniqueStudy) {
$keysFromStudies = array_keys(array_filter($t['studies'], function($x) use ($uniqueStudy) {
return $x === $uniqueStudy;
}));
$averages[] = round(
(
array_sum(array_intersect_key($t['notesC'], array_flip($keysFromStudies))) /
array_sum(array_intersect_key($t['denumsC'], array_flip($keysFromStudies)))
) * 20,
1
);
}
$tabAssoForBar[$id] = [
'id' => $t['id'],
'name' => $t['name'],
'studies' => array_values($uniqueStudies),
'averages' => $averages
];
}
print_r($tabAssoForBar);
Output
Array
(
[51] => Array
(
[id] => 51
[name] => JOHN
[studies] => Array
(
[0] => math
[1] => LV1
[2] => history
)
[averages] => Array
(
[0] => 14.5
[1] => 9.3
[2] => 9.8
)
)
)
See a php demo
I've a muti dimensional array. I want to concatenate 2 strings separately for 2 array values and the 2 strings should not be concatenated for a single value. I want CM and PM concatenated 2 times any where in the array. I've tried looping the array and generating array_rand but i generates only once. Any help is much appreciated. Below is one example of what am achieving.
Thing am trying to achieve
Concatenate "PM" and "CM" string in one set of array and same value can't be CM and PM
Every array should have PM and CM concatenated
1 "Name" value should have minimum 1 CM and PM and Maximum 2 CM and PM
For example: I've the below multi dimensional array.
Array
(
[0] => Array
(
[0] => Name-A
[1] => Name-B
[2] => Name-C
[3] => Name-4
[4] => Name-5
)
[1] => Array
(
[0] => Name-A
[1] => Name-B
[2] => Name-C
[3] => Name-4
[4] => Name-5
)
[2] => Array
(
[0] => Name-A
[1] => Name-B
[2] => Name-C
[3] => Name-4
[4] => Name-5
)
[3] => Array
(
[0] => Name-A
[1] => Name-B
[2] => Name-C
[3] => Name-4
[4] => Name-5
)
[4] => Array
(
[0] => Name-A
[1] => Name-B
[2] => Name-C
[3] => Name-4
[4] => Name-5
)
)
After concatenating
Array
(
[0] => Array
(
[0] => Name-A
[1] => Name-B
[2] => Name-C["PM"]
[3] => Name-4["CM"]
[4] => Name-5
)
[1] => Array
(
[0] => Name-A
[1] => Name-B["PM"]
[2] => Name-C
[3] => Name-4["CM"]
[4] => Name-5
)
[2] => Array
(
[0] => Name-A["PM"]
[1] => Name-B
[2] => Name-C
[3] => Name-4
[4] => Name-5["CM"]
)
[3] => Array
(
[0] => Name-A["PM"]
[1] => Name-B["CM"]
[2] => Name-C
[3] => Name-4
[4] => Name-5
)
[4] => Array
(
[0] => Name-A
[1] => Name-B
[2] => Name-C["CM"]
[3] => Name-4
[4] => Name-5["PM"]
)
)
Sorry I didn't understand at first.
Given $your_array:
// Generate an array where the names are the key, and assign a zero value to PM (0) and CM (1) in a sub array
$ar = array_fill_keys($your_array[0], array (0 => 0, 1 => 0));
//$array the sub_value, $add the case PM ou CM, $exclusion is the key used the first time
function rand_in_array($array, $add, $ar, $exclusion)
{
// Select a random key
$arr_key = array_rand($array, 1);
if($ar[$array[$arr_key]][$add] < 2 && ($arr_key != $exclusion))
{
return $arr_key;
}
return rand_in_array($array, $add, $ar, $exclusion);
}
for($i=0; $i<count($your_array);$i++)
{
$arr_key_pm = rand_in_array($your_array[$i], 0, $ar, 99);
$ar[$your_array[$i][$arr_key_pm]][0]++;
$arr_key_cm = rand_in_array($your_array[$i], 1, $ar, $arr_key_pm);
$ar[$your_array[$i][$arr_key_cm]][1]++;
$your_array[$i][$arr_key_pm] .= "PM";
$your_array[$i][$arr_key_cm] .= "CM";
}
It is ugly but it works :)
Somewhere should existe someone able to make more aesthetic..
for($i=0; $i<count($your_array);$i++)
{
$arr_keys = array_rand($your_array[$i], 2);
$your_array[$i][$arr_keys[0]] .= "PM";
$your_array[$i][$arr_keys[1]] .= "CM";
}
Should do the work.
I assume your inner array index is starting from zero. So generate the random index between 0 to your ( inner_array_size - 1). Then assign the value in the array's reference variable withing the loop.
foreach ($arr as &$value) {
$randomIndex = array_rand(range(0, (count($value) -1) ), 2);
$value[$randomIndex[0]] .= ' ["CM"]';
$value[$randomIndex[1]] .= ' ["PM"]';
}
I want to build a array or multiple array by breaking the main array , and my array is like ,
Array
(
[0] => string1
[1] => 1
[2] => 2
[3] => 3
[4] => 66
[5] => 34
[6] => string1
[7] => aww
[8] => brr
[9] => string3
[10] => xas
)
So basically by the value 'string1' i want to make a new array or first array which has only those three values (1,2,3) and same for string2 and string3,So each array has its values(three).
Please help me to build this.
Note: those all string names will be static.
Thank you in advance.
Result should me like:
string1 array:
<pre>Array
(
[1] => 1
[2] => 2
[3] => 3
[4] => 66
[5] => 34
)
string2 array:
<pre>Array
(
[1] => aww
[2] => brr
)
string3 array:
<pre>Array
(
[1] => xas
)
This I think will get you what you want.
It does assume that the first entry in the old array will be a keyword!
$old = array('string1',1,2,3,66,34,'string2','aww','brr','string3','xas');
$new = array();
$keywords = array('string1', 'string2', 'string3');
$last_keyword = '';
foreach ($old as $o) {
if ( in_array($o, $keywords) ) {
$last_keyword = $o;
} else {
$new[$last_keyword][] = $o;
}
}
print_r($new);
It creates a new array like this
Array
(
[string1] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 66
[4] => 34
)
[string2] => Array
(
[0] => aww
[1] => brr
)
[string3] => Array
(
[0] => xas
)
)
However I still maintain that it would be better to go back to where the original array gets created and look to amend that process rather than write a fixup for it
I have arrays like this
Array 1:
Array
(
[0] => Array
(
[0] => 0
[1] => -0.025
)
[1] => Array
(
[0] => 0
[1] => -0.025
)
[2] => Array
(
[0] => 0
[1] => -0.025
)
)
Array 2:
Array
(
[0] => Array
(
[0] => 0
[1] => -0.025
)
[1] => Array
(
[0] => 0
[1] => -0.025
)
)
Array 3:
Array
(
[0] => Array
(
[0] => 0
[1] => -0.025
)
[1] => Array
(
[0] => 0
[1] => -0.025
)
[2] => Array
(
[0] => 0
[1] => -0.025
)
[3] => Array
(
[0] => 0
[1] => -0.025
)
)
and more of them.
I want to combine them to this
Array
(
[0] => Array
(
[0] => 0
[1] => -0.025
[2] => 0
[3] => -0.025
[4] => 0
[5] => -0.025
)
[1] => Array
(
[0] => 0
[1] => -0.025
[2] => 0
[3] => -0.025
[4] => 0
[5] => -0.025
)
[2] => Array
(
[0] => 0
[1] => -0.025
[2] => 0
[3] => 0
[4] => 0
[5] => -0.025
)
[3] => Array
(
[0] => 0
[1] => 0
[2] => 0 // These (0-3) are 0 because the other two arrays haven't 3 in the first level
[3] => 0
[4] => 0
[5] => -0.025
)
)
The arrays have a different number of entries in the first level. In the second level there are always 2 entries.
In the second level of the combined array the first two keys (0 and 1) should always have the entries from the first array. The second two keys (2 and 3) should always have the entries from the second array and so on. In my example there are 30 arrays that I want to combine.
If an array does have more first level entries than others all entries should have 0 as value.
I hope you understand this :)
I built it ;-/
Working demonstration at eval.in
Requirements:
Basically it is transposing rows into columns.
the output columns all have the length of the longest array.
The source arrays can have different lengths. Any empty entries are assumed to have a value of array(0, 0).
The output columns are converted into a single dimensional array. i.e. source value arrays are appended to the column array.
Explanation:
I decided to use the internal iterator that all arrays have. i.e. the arrays already can record there own state such as current position (row) that they are on.
After that it is just 'housekeeping':
keep a list of which arrays still have entries to be processed. When none of them have then we are finished.
record which output column ($mergedEntryNo) that we are creating.
scan along each (row) reading entries for the current row.
after each row: advance to the next row and record which arrays are active - if any.
The class (SimpleMerge) that does the work
class SimpleMerge {
protected $sources = array(); // a list of arrays!
protected $sourceCount = 0; // useful
protected $isActive = array(); // which of them have entries to process.
public $merged = array(); // output in here and public
protected $anyActiveSources = false;
// need a list of arrays
public function __construct(array $allSources)
{
$this->sources = $allSources;
$this->sourceCount = count($allSources);
$this->isActive = array_fill(0, $this->sourceCount, true);
}
// generate the output by scanning the arrays line by line
public function generateOutput()
{
$this->generateInit();
$mergedEntryNo = 0;
while ($this->anyActiveSources) {
// set the next output entries
for ($sourceNo = 0; $sourceNo < $this->sourceCount; $sourceNo++) {
$this->addEntry($mergedEntryNo, $this->getEntry($sourceNo));
}
$mergedEntryNo++;
$this->nextPassAdvance();
$this->setIsActiveSource();
}
return $this->merged;
}
// ensure everything is initialized correctly
public function generateInit()
{
$this->merged = array();
foreach ($this->sources as &$source) {
reset($source); // force internal iterators to the start
$this->merged[] = array(); // empty arrays in the output
}
unset($source);
$this->setIsActiveSource();
}
// add to output
public function addEntry($mergedNo, array $values)
{
foreach ($values as $value) {
$this->merged[$mergedNo][] = $value;
}
}
// get the current source entry - will be array of zeroes if end of array
public function getEntry($sourceNo)
{
if ($this->isActive[$sourceNo]) {
return current($this->sources[$sourceNo]);
}
else {
return array(0, 0);
}
}
// check and set which ones are still active and also indicate if any are active
public function setIsActiveSource()
{
$activeCount = 0;
for ($sourceNo = 0; $sourceNo < $this->sourceCount; $sourceNo++) {
$isActive = current($this->sources[$sourceNo]) !== false;
$this->isActive[$sourceNo] = $isActive;
$activeCount = $activeCount + ($isActive ? 1 : 0);
}
$this->anyActiveSources = $activeCount > 0;
}
// advance iterators on the sources that are still active
public function nextPassAdvance()
{
for ($sourceNo = 0; $sourceNo < $this->sourceCount; $sourceNo++) {
if ($this->isActive[$sourceNo]) { // was last time
next($this->sources[$sourceNo]);
}
}
}
}
Run it
// create and run the generator...
$mergeAll = new SimpleMerge($allSourcesList);
$merged = $mergeAll->generateOutput();
Output:
Note, there are no zero values in the input. The values indicate source table and entry number.
Outpt: Array
(
[0] => Array
(
[0] => 11
[1] => -11.025
[2] => 21
[3] => -21.025
[4] => 31
[5] => -31.025
[6] => 41
[7] => -41.025
)
[1] => Array
(
[0] => 12
[1] => -12.025
[2] => 22
[3] => -22.025
[4] => 32
[5] => -32.025
[6] => 42
[7] => -42.025
)
[2] => Array
(
[0] => 13
[1] => -13.025
[2] => 0
[3] => 0
[4] => 33
[5] => -33.025
[6] => 43
[7] => -43.025
)
[3] => Array
(
[0] => 0
[1] => 0
[2] => 0
[3] => 0
[4] => 34
[5] => -34.025
[6] => 44
[7] => -44.025
)
)
So I have an array such as this one:
Array
(
[-1] => Array
(
[3] => 3
[1] => 1
[6] => 6
[7] => 7
[5] => 5
)
)
It also contains some other keys that should not be modified.
I'd like to the numbers which are in a second array to come first (in the order of that second array), and then will be the numbers that don't exist in the second array, if any.
So for that matter, the second array would be:
Array
(
[0] => 6
[1] => 5
[2] => 3
)
And the final array should be as follows (please remember, there are some more keys inside of that array that should stay as they are):
Array
(
[-1] => Array
(
[6] => 6
[5] => 5
[3] => 3
[1] => 1
[7] => 7
)
)
Any ideas how that can be done?
Thanks!
It's not and shouldn't be termed as sorting but may be this code snippet may help you do what you want to:
$a1 = Array ( [-1] => Array ( [3] => 3 [1] => 1 [6] => 6 [7] => 7 [5] => 5 ) );
$a2 = Array ( [0] => 6 [1] => 5 [2] => 3 );
$sorted = getSortedArray($a1[-1] , $array2);
function getSortedArray($array1 , $array2){
$temp = Array();
$count = 0;
$totalKeys = sizeof($array2);
for($i=0;$i<sizeof($array2);$i++){
$temp[i] = $array1[$array2[i]];
unset($array1[$array2[i]]);
}
while($count!=sizeof($array1))
$temp[$totalKeys++] = $array1[$count++];
return $temp;
}
I believe the function you're looking for is called array_multisort().
array_multisort() can be used to sort
several arrays at once, or a
multi-dimensional array by one or more
dimensions.