I have array like this
$arr=[["a","b"],["b","c"],["d","e"],["f","c"]];
if sub arrays share same value they should be be merged to one array
expected output:
$arr=[["a","b","c","f"],["d","e"]];
I`m trying to avoid doing foreach inside foreach for solving this.
It seems your inner arrays always have 2 items. so nested loops aren't necessary. Here is a solution which I originally wrote in JS but it should work just as good and most efficient in PHP:
$arr=[["a","b"],["b","c"],["d","e"],["f","c"],["h","e"]];
$output = [];
$outputKeys = [];
$counter = 0;
foreach($arr as $V) {
if(!isset($outputKeys[$V[0]]) && !isset($outputKeys[$V[1]])) {
$output[$counter] = [$V[0], $V[1]];
$outputKeys[$V[0]] = &$output[$counter];
$outputKeys[$V[1]] = &$output[$counter];
$counter++;
}
elseif(isset($outputKeys[$V[0]]) && !isset($outputKeys[$V[1]])) {
array_push($outputKeys[$V[0]], $V[1]);
$outputKeys[$V[1]] = &$outputKeys[$V[0]];
}
elseif(!isset($outputKeys[$V[0]]) && isset($outputKeys[$V[1]])) {
array_push($outputKeys[$V[1]], $V[0]);
$outputKeys[$V[0]] = &$outputKeys[$V[1]];
}
}
var_dump($output); // [["a","b","c","f"],["d","e","h"]]
DEMO (click the execute button)
Pointers are your friends. Use them :)
The following algorithm should do what you want. It simply checks through each item and checks if it already exists in the newly created array, and if it does it adds it to that item instead of a new one:
<?php
$arr=[["a","b"],["b","c"],["d","e"],["f","c"]];
$newArr = [];
foreach ($arr as $items) {
$newKey = null;
foreach ($items as $item) {
foreach ($newArr as $newItemsKey => $newItems) {
if (in_array($item, $newItems)) {
$newKey = $newItemsKey;
break 2;
}
}
}
if ($newKey !== null) {
$newArr[$newKey] = array_merge($newArr[$newKey], $items);
} else {
$newArr[] = $items;
}
}
$newArr = array_map('array_unique', $newArr);
print_r($newArr);
Output:
Array
(
[0] => Array
(
[0] => a
[1] => b
[3] => c
[4] => f
)
[1] => Array
(
[0] => d
[1] => e
)
)
DEMO
This is solution I get for now.
$arr=[["a","b","c","f"],["d","e"]];
$sortedArray = sortFunction($arr,0,array());
function sortFunction($old,$index,$new) {
if ($index == sizeof($old)) return $new;
for ($i = 0; $i<sizeof($new); $i++) {
if (count(array_intersect($new[$i],$old[$index]))) {
$new[$i] = array_unique(array_merge($old[$index],$new[$i]), SORT_REGULAR);
return sortFunction($old,$index + 1,$new);
}
}
$new[] = $old[$index];
return sortFunction($old,$index + 1,$new);
}
Related
I am trying to rank an array of values and maintain the order in the original array.
So for example:
(6,4,7,12,7) should return (2,1,3,4,3)
(12,17,5,27,5) should return (2,3,1,4,1)
(1,1,4,6) should return (1,1,2,3)
In each case the returned array has the rank of the corresponding element in the original array, and duplicate values will have the same rank.
$values = array(12,17,5,27,5);
$sorted_values = $values;
sort($sorted_values);
foreach ($values as $key => $value) {
foreach ($sorted_values as $sorted_key => $sorted_value) {
if ($value == $sorted_value) {
$rank_key = $sorted_key;
break;
}
}
echo $value . ' has rank: ' . $rank_key + 1 . '<br>';
}
A simple way would be to first rank the unique values (using array_unique() followed by sort()), then translate the original list by this newly rank list (more comments in the code)...
$source = [12,17,5,27,5];
$output = [];
// Copy to work array unique values
$rank = array_unique($source);
// Sort it to produce ranking order
sort($rank);
// Make the number the key with the order as the value
$rank = array_flip($rank);
// Translate the values using $rank
foreach ( $source as $element ) {
$output[] = $rank[$element]+1;
}
print_r($output);
gives...
Array
(
[0] => 2
[1] => 3
[2] => 1
[3] => 4
[4] => 1
)
Clone your array, sort the clone by values, while keeping the key associations.
Loop over the clone, and in classical “control break” fashion, compare the value of the current item to that of the previous one. Increase the rank by one, if they differ. Set that rank as new value under that key.
Sort the clone by keys.
$data = [12,17,5,27,5];
$clone = $data;
asort($clone);
$rank = 0;
$previous_value = null; // something that doesn't ever occur in your array values
foreach($clone as $key => $value) {
if($value !== $previous_value) {
$rank++;
}
$clone[$key] = $rank;
$previous_value = $value;
}
ksort($clone);
var_dump($data, $clone);
you need to sort your array
This may close to your answer:
<?php
$my_array=array(12,17,5,27,5);
$ordered_values = $my_array;
$rank=array();
rsort($ordered_values);
foreach ($ordered_values as $key => $value) {
foreach ($ordered_values as $ordered_key => $ordered_value) {
if ($value === $ordered_value) {
$key = $ordered_key;
break;
}
}
$rank[$value]=((int) $key + 1) ;
}
foreach($my_array as $key => $value)
{
echo $value.':'.$rank[$value].'<br>';
}
?>
function rankDuplicateArray(array $array): array
{
$copy = array_unique($array);
sort($copy);
$flipArray = array_flip($copy);
return array_map(function($v) use ($flipArray) {
return $flipArray[$v] + 1;
}, $array);
}
$feetypes=[
[30,35,50],
[30,35],
[30,50],
[30,34]
];
i have this code, want to count as per there value like count 30*4, 35*2, 50*2 & 34*1.
i have already tried:
$counts = array();
foreach ($array as $key=>$subarr) {
// Add to the current group count if it exists
if (isset($counts[$subarr['group']]) {
$counts[$subarr['group']]++;
}
// or initialize to 1 if it doesn't exist
else $counts[$subarr['group']] = 1;
// Or the ternary one-liner version
// instead of the preceding if/else block
$counts[$subarr['group']] = isset($counts[$subarr['group']]) ? $counts[$subarr['group']]++ : 1;
}
but my problem still there
You can merge all the inner arrays into one with array_merge and then use array_count_values to get the counts.
$counts = array_count_values(array_merge(...$feetypes));
Merge all the subarray into a single array and apply array_count_values function to get the result
function merageAll($arr) {
$flatArray = array();
foreach($arr as $element) {
if (is_array($element)) {
$flatArray = array_merge($flatArray, merageAll($element));
} else {
$flatArray[] = $element;
}
}
return $flatArray;
}
$res = array_count_values(merageAll($feetypes));
Result
Array
(
[30] => 4
[35] => 2
[50] => 2
[34] => 1
)
function merageAll work if there are values and sub arrays in the array.
Working DEMO LINK
I used recursion in case values are more than two levels deep. note the $count variable is passed by reference to the function due to recursion.
<?php
$feetypes=[
[30,35,50],
[30,35],
[30,50],
[30,34]
];
$counts = array();
function countValues($arr, &$count) {
foreach($arr as $subval) {
if(is_array($subval)) {
countValues($subval,$count);
} else {
if(isset($count[$subval])) {
$count[$subval] += 1;
} else {
$count[$subval] = 1;
}
}
}
}
countValues($feetypes,$counts);
print_r($counts);
<?php
function tambah_penumpang($daftar_penumpang, $penumpang_baru){
if(empty($namaArray)==true){
$daftar_penumpang[]=$penumpang_baru;
return $daftar_penumpang;
}else{
for($i=0; $i<count($daftar_penumpang); $i++){
if($daftar_penumpang[$i]== null){
$daftar_penumpang[$i]=$penumpang_baru;
return $daftar_penumpang;
}else{
$daftar_penumpang[] = $penumpang_baru;
return $daftar_penumpang;
}
}
}
}
$daftar_penumpang =["sandhika",null,"carl","keith"];
print_r(tambah_penumpang($daftar_penumpang,"anggoro"))."<br>"
?>
And this are the result: (i want that anggoro name in null's index)
Array (
[0] => sandhika
[1] =>
[2] => carl
[3] => keith
[4] => anggoro
)
as I'm not familiar with your naming convention , i've made a global example using array_walk as follows:
$daftar_penumpang =["sandhika",null,"carl","keith"];
array_walk($daftar_penumpang, function($v, $k, $replacement) use (&$daftar_penumpang) {
if ($v == null) {
$daftar_penumpang[$k] = $replacement;
}
}, 'anggoro');
print_r($daftar_penumpang);
live example: https://3v4l.org/vVnSq
for your case :
$daftar_penumpang =["sandhika",null,"carl","keith"];
function tambah_penumpang($daftar_penumpang, $penumpang_baru) {
array_walk($daftar_penumpang, function($v, $k, $replacement) use (&$daftar_penumpang) {
if ($v == null) {
$daftar_penumpang[$k] = $replacement;
}
}, $penumpang_baru);
return $daftar_penumpang;
}
print_r(tambah_penumpang($daftar_penumpang, 'anggoro'));
this will output:
Array ( [0] => sandhika [1] => anggoro [2] => carl [3] => keith )
Update
using for loop :
your code issue is that you will never ever get into the for loop because it is in else condition , and while the $namaArray is alway empty, so you will never go through the loop , so i've removed this check and prepared this looping to show you how to replace null values using for loop
function tambah_penumpang($daftar_penumpang, $penumpang_baru)
{
$tmpArray = [];
for ($i=0; $i < count($daftar_penumpang); $i++) {
if ($daftar_penumpang[$i]== null) {
$tmpArray[$i] = $penumpang_baru;
} else {
$tmpArray[] = $daftar_penumpang[$i];
}
}
return $tmpArray;
}
$daftar_penumpang =["sandhika",null,"carl","keith"];
print_r(tambah_penumpang($daftar_penumpang,"anggoro"));
Try with this function :
<?php
function tambah_penumpang($daftar_penumpang, $penumpang_baru){
$datas = [];
for($i = 0; $i < count($daftar_penumpang); $i++) {
$item = $daftar_penumpang[$i];
if($item === null) {
$item = $penumpang_baru;
}
$datas[$i] = $item;
}
return $datas;
}
$daftar_penumpang =["sandhika",null,"carl","keith"];
print_r(tambah_penumpang($daftar_penumpang,"anggoro"))."<br>";
i want so replace something in a array, but the array isn´t sorted. So maybe you know how i can fix the problem.
I´ve a array with a few of this element.
<media type="image" id="image5" label="book5.jpg" group="image" source="list2/Schuh2.jpg" url="image5/0.jpg" icon="image5/0.jpg"/>
How can i sort the array by the value of lable? so that first i get for example from
Lables:
book3
book4
book2
-->
book2
book3
book4
i hope you know what i mean :D thank you ;-)
$books = array('book3', 'book4', 'book2');
sort($books);
or
$books = array('label1' =>'book5.jpg',
'label2' => 'book4.jpg', 'label3' => 'book3.jpeg');
asort($books); // sorts by value (ascending)
hope this helps!
Hack
foreach($a as $k => $media) {
$parts = explode(' ',$media);
foreach($parts as $part) {
$kv = explode('=', $part);
if ($kv[0] == 'label') {
$a[$kv[1]] = $media;
unset($a[$k]);
}
}
}
ksort($a);
or look at usort() which let you use your own comparison function
Assuming unique book#.jpg images you could do something like ...
<?php
$sortedArray = array();
foreach ($unsortedArray as $item ) {
$sortedArray[explode('.', explode('label="book', $item)[1])[0]] = $item;
}
ksort($sortedArray);
foreach ($sortedArray as $item ) {
echo $item;
}
?>
I did not test this.
UPDATE:
Someone else's suggestion to use usort() is a good one. Something like this ...
<?php
function compareElements($a, $b) {
$aNum = explode('.', explode('label="book', $a)[1])[0];
$aNum = explode('.', explode('label="book', $b)[1])[0];
return ($aNum < $bNum) ? -1 : 1;
}
usort($arrayOfElements, "compareElements");
foreach ($arrayOfElements as $element) {
echo $element;
}
?>
The Problem was, that i can´t sorte bei the one value ['id'] so i has create me one array with all the Informations, and a second only with the ['id'] of the pictures.
Input and load the XML-File.
$mashTemplateFile = 'C:\Users\...\test.xml';
$mashTemplate = simplexml_load_file($mashTemplateFile);
$mash = $mashTemplate->mash;
declare the arry's
$imageArrayMedTemp = array();
$imageArrayMedID = array();
$imageArrayMed = array();
put all the information from the media in the array $imageArrayMedTemp and only the ['id']into the array $imageArrayMedID.
foreach ($mash->media as $med) {
if ($med['type'] == 'image') {
array_push($imageArrayMedTemp , $med);
array_push($imageArrayMedID , $med['id']);
}
now i sort the array with the ['id']'s
natsort($imageArrayMedID);
after sorting i will put the information from the array $imageArrayMedTemp into a new array $imageArrayMed, storing by when the key of both is the same.
foreach ($imageArrayMedID as $key1 => $value1) {
foreach ($imageArrayMedTemp as $key2 => $value2) {
if($key1 == $key2){
array_push($imageArrayMed,$value2);
}
}
}
I am trying to get my head around arrays.
The arrays should look like this:
$questions[$a] => array( [0] => No, comment1
[1] => Yes, comment2
[2] => No, comment3 )
$answer[$a] => array( [0] => No
[1] => Yes
[3] => No )
$comment[$a] => array( [0] => comment1
[1] => comment2
[3] => comment3 )
=========================================================================
SECOND EDIT: Need to execute this in the loop to create a third array -
if($answer[$a] == "Yes") { $display[$a] = "style='display:none'";
} else { $display[$a] = "style='display:block'"; }
This is what i have: (28th for minitech)
while ($a > $count)
{
if($count > 11) {
foreach($questions as $q) {
list($answer, $comments[]) = explode(',', $q);
if($answer === "Yes") {
$display[$a] = "style='display:none'";
} else {
$display[$a] = "style='display:block'";
}
$answers[] = $answer;
}
}
$a++;
}
If they are actually strings, explode works:
$answers = array();
$comments = array();
$display = array();
foreach(array_slice($questions, 11) as $question) {
list($answer, $comments[]) = explode(',', $question);
$display[] = $answer === 'Yes' ? 'style="display: none"' : 'style="display: block"';
$answers[] = $answer;
}
Here’s a demo!
Change your while loop to this
while ...
{
$parts = explode(',', $questions[$a]);
$answer[$a][] = trim($parts[0]);
$comment[$a][] = trim($parts[1]);
}
In your original code you were overwriting the $answer[$a] and $comment[$a] each time, not appending to the end of an array
$questions[$a] = array('Q1?' => 'A1', 'Q2?' => 'A2', 'Q3?' => 'A3');
foreach($questions[$a] as $key => $value)
{
$comment[$a][] = $key;
$answer[$a][] = $value;
}
This should work.
foreach ($questions[$a] as $key=>$value){
$temp = explode(',',$value);
$answer[$key] = $temp[0];
$comment[$key] = $temp[1];
}
$key will have 0,1,2 respectively. $value will have the values for each $question[$a](No,Comment1 ....)
Can't think of a funky one-liner, but this should do it:
foreach ($questions as $a => $entries) {
foreach ($entries as $k => $entry) {
$parts = array_map('trim', explode(',', $entry));
$answer[$a][$k] = $parts[0];
$comment[$a][$k] = $parts[1];
}
}
$questions = array( 0 => 'No,comment1',1 => 'Yes,comment2',2 => 'No,comment3' );
foreach($questions as $question)
{
$parts = explode(",",$question);
$answer[] = $parts[0];
$comment[] = $parts[1];
}
echo "<pre>";
print_r($answer);
print_r($comment);
Here is the right answer
foreach($questions as $key => $question){
foreach($question as $q => $data){
$data= explode(',',$data);
$comments[$key][$q] = $data[0];
$answer[$key][$q] = $data[1];
}
}
If the values in $questions are comma-separated strings you could use an array_walk function to populate your $answer and $comment arrays
$question = array(...); //array storing values as described
$answer = array();
$comment = array();
array_walk($question, function ($value, $key) use ($answer,$comment) {
$value_array = explode(',', $value);
$answer[$key] = $value_array[0];
$comment[$key] = $value_array[1];
});
Note that this is shown using an anonymous function (closure) which requires PHP >= 5.3.0. If you had a lower version of PHP, you would need to declare a named function, and declare $answer and $comment as globals in the function. I think this is a hacky approach (using globals like this) so if I was using PHP < 5.3 I would probably just use a foreach loop like other answers to your question propose.
Functions like array_walk, array_filter and similar functions where callbacks are used are often great places to leverage the flexibility provided by anonymous functions.