This question already has answers here:
Add elements to array which has gapped numeric keys to form an indexed array / list
(5 answers)
Closed 5 months ago.
I have a following indexed array
$export_data = array (
[0] => 1,
[1] => 2,
[2] => 3,
[3] => 4,
[4] => 5,
[8] => 9,
[9] => 10,
);
I know how to export it to csv using fputcsv. However what my issue is that I need to export the data into correct column i.e. value in $export_data[8] needs to be exported in column 9 not column 6.
How can this be done please ?
Here you go, boss.
$export_data = array_replace(array_map(function($v){return null;}, range(0, max(array_keys($export_data)))), $export_data);
Tested 100,000 iterations and results are in seconds:
Version Run1 Run2 Run3
PHP 5.6.20 .58 .55 .50
PHP 7.0.5 .18 .21 .21
Now for the explanation so I don't get flogged with downvotes or get accused of witchcraft.
$export_data = array (
0 => 1,
1 => 2,
2 => 3,
3 => 4,
4 => 5,
8 => 9,
9 => 10,
);
$export_data =
array_replace( // replace the elements of the 10-item array with your original array and the filled-in blanks are going to be null. I did not use array_merge() because it would append $export_data onto our dynamic range() array rather than replacing elements as needed.
array_map( // loop the 10-item array and apply the declared function per element. This function ends up returning the 10-item array with all keys intact but the values will be null
function($v){return null; /* return ''; // if you prefer and empty string instead of null*/}, // set each value of the 10-item array to null
range( // create an 10-item array with indexes and values of 0-9
0,
max(array_keys($export_data)) // get the highest key of your array which is 9
)
),
$export_data // your original array with gaps
);
var_dump($export_data);
print_r($export_data);
if i understand correctly, you want to put free columns between data, so the keys match column number.
$arr = array(
0 => 1,
1 => 2,
2 => 3,
3 => 4,
4 => 5,
8 => 9,
9 => 10,
);
$csvArray = array();
$maxKey = max(array_keys($arr));
for($i = 0; $i <= $maxKey; $i++){
if(array_key_exists($i, $arr)){
$csvArray[$i] = $arr[$i];
} else {
$csvArray[$i] = null;
}
}
print_r($csvArray);
demo here: live demo
to describe it, just cycle through array and check wether key is set, if is, assing its value to the next array, if is not, assign null
Optimized:
$csvArray = array();
$maxKey = max(array_keys($arr));
// ++$i is microscopically faster when going for the long haul; such as 10,000,000 iterations
// Try it for yourself:
// $start = microtime(true);
// for($i=0; $i<10000000; $i++){}
// echo (microtime(true) - $start).' seconds';
for($i = 0; $i <= $maxKey; ++$i){
// we can use isset() because it returns false if the value is null anyways. It is much faster than array_key_exists()
$csvArray[$i] = (isset($arr[$i]) ? $arr[$i] : null);
}
I would just fill the array completely with empty values for the empty columns:
$export_data = array (
[0] => 1,
[1] => 2,
[2] => 3,
[3] => 4,
[4] => 5,
[5] => '',
[6] => '',
[7] => '',
[8] => 9,
[9] => 10,
);
Without the indexes (because they are automatic in any case):
$export_data = array (
1,
2,
3,
4,
5,
'',
'',
'',
9,
10,
);
Related
I have this code:
$ItemID = 'a62442e2-ca1f-4fd1-b80d-0d0dc511758e';
$GET_FreeTextFields = new \Picqer\Financials\Exact\ItemExtraField($connection);
$FreeTextFields = $GET_FreeTextFields->filter("ItemID eq guid'$ItemID'", '', '' );
$FreeTextFields01 = array();
$FreeTextFields02 = array();
foreach($FreeTextFields as $GET_FreeTextFields){
$FreeTextFields01[] = $GET_FreeTextFields->Value;
$FreeTextFields02[] = $GET_FreeTextFields->Number;
}
print_r($FreeTextFields01);
print_r($FreeTextFields02);
This outputs:
Value Array
(
[0] => 390
[1] => 804715
[2] => WW001
[3] => WHT/WHT/WHT
[4] => 39/42
[5] => 804715 WW00139/42
[6] => 3pk Quarter Socks
)
Numbers Array
(
[0] => 3
[1] => 4
[2] => 5
[3] => 6
[4] => 7
[5] => 8
[6] => 10
)
What this needs to output:
What i want if i use the first output so with 6 values in the array:
$FreeTextField01 = null
$FreeTextField02 = null
$FreeTextField03 = 390
$FreeTextField04 = 804715
$FreeTextField05 = WW001
$FreeTextField06 = WHT/WHT/WHT
$FreeTextField07 = 39/42
$FreeTextField08 = 804715 WW00139/42
$FreeTextField09 = null
$FreeTextField10 = 3pk Quarter Socks
But with other $ItemID, it can also output:
Value Array
(
[0] => 10100153
[1] => 2007
[2] => 350
[3] => 804082
[4] => WW006
[5] => WHT/NNY/OXGM
[6] => 35/38
[7] => 804082 WW00635/38
[8] => 0,00138857
[9] => Champion 3pk Quarter Socks
)
Numbers Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
[6] => 7
[7] => 8
[8] => 9
[9] => 10
)
What i want is that if a variable is not in the numbers list so 1-10, setting it to empty, and if the numbers is in the numbers array setting that number to the corresponding value variable. For example the number at [0] is 1 then set the variable $FreeTextField1 to $NumbersArray[0]->Value.
I keep making all kinds off loops but i just get stuck at the fact that the array length changes so that [6] can be the number 10 at one $itemID, but at another $ItemID, the number can be 6.
I tried researching this but I don't even know what I have to type in google to find this problem, that's why I'm describing it here.
edit i tried describing it a second time:
Yeah I'm having problems describing what i want, so let me try again. I get two arrays as output one with numbers that correspond with place it stands, as example you have FreeTextField0 thru FreeTextField10. What i tried to do is if (Numbers[0] == 0){ $FreeTextField0 = Value[0]}, but then I get the problem that Numbers[0] can be 3 or something else because if FreeTextField1 is empty i don't get a null value but nothing.
What i want if i use the first output so with 6 values in the array:
$FreeTextField01 = null
$FreeTextField02 = null
$FreeTextField03 = 390
$FreeTextField04 = 804715
$FreeTextField05 = WW001
$FreeTextField06 = WHT/WHT/WHT
$FreeTextField07 = 39/42
$FreeTextField08 = 804715 WW00139/42
$FreeTextField09 = null
$FreeTextField10 = 3pk Quarter Socks
I think this is what you're after but I have to say that I think you're barking up the wrong tree here. You really should not dynamically create variables in your script. To me, it is a serious code-smell and I think you should evaluate your design here.
http://sandbox.onlinephpfunctions.com/code/b245a0218ce174e68508139872f394def5409b05
<?php
// Test case
$values = [
'390',
'804715',
'WW001',
'WHT/WHT/WHT',
'39/42',
'804715 WW00139/42',
'3pk Quarter Socks'
];
$numbers = [3, 4, 5, 6, 7, 8, 10];
// Flip the $numbers array and then use the keys to find the corresponding values in the $values array
$intersection = array_unique(array_intersect_key($values, array_flip($numbers)));
// Fill in the missing keys and use `null` as the value
$output = $intersection + array_fill_keys(range(1,10), null);
// Sort the final output by the keys
ksort($output);
// Format the keys to match FreeTextField{00}
$output = array_combine(
array_map(function($k){ return 'FreeTextField'.str_pad($k, 2, '0', STR_PAD_LEFT); }, array_keys($output)),
$output
);
// Use the extract function to bring all those array keys + values into the symbol table.
// You can now use $FreeTextField01 - $FreeTextField10
extract($output);
var_dump($output);
UPDATE
http://sandbox.onlinephpfunctions.com/code/244c4f1ed45db398c48b8330c402b375eb358446
<?php
// Test case
$input = [
['Value' => '390', 'Number' => 3],
['Value' => '804715', 'Number' => 4],
['Value' => 'WW001', 'Number' => 5],
['Value' => 'WHT/WHT/WHT', 'Number' => 6],
['Value' => '39/42', 'Number' => 7],
['Value' => '804715 WW00139/42', 'Number' => 8],
['Value' => '3pk Quarter Socks', 'Number' => 10],
];
$intersection = [];
foreach ($input as $config) {
$value = $config['Value'];
$number = $config['Number'];
$intersection[$number] = $value;
}
// Fill in the missing keys and use `null` as the value
$output = $intersection + array_fill_keys(range(1,10), null);
// Sort the final output by the keys
ksort($output);
// Format the keys to match FreeTextField{00}
$output = array_combine(
array_map(function($k){ return 'FreeTextField'.str_pad($k, 2, '0', STR_PAD_LEFT); }, array_keys($output)),
$output
);
// Use the extract function to bring all those array keys + values into the symbol table.
// You can now use $FreeTextField01 - $FreeTextField10
extract($output);
var_dump($output);
Use ${$var}
If you want to see a doc about this type of var you can see it here:
http://php.net/manual/en/language.variables.variable.php
I have a multidimensional array:
$array =
Array (
[0] => Array ( [id] => 2 [zoneId] => 2 [buildingId] => 2 [typeId] => 2 )
[1] => Array ( [id] => 4 [zoneId] => 2 [buildingId] => 2 [typeId] => 1 )
[2] => Array ( [id] => 6 [zoneId] => 6 [buildingId] => 17 [typeId] => 2 ) )
And I would like to search if the combination of, for example, [buildingId] => 2, [typeId] => 2 exists is array 0, 1 or 2.
I tried the following:
$keyType = array_search(2, array_column($array, 'typeId'));
$keyBuilding = array_search(2, array_column($array, 'buildingId'));
if(is_numeric($keyType)&&is_numeric($keyBuilding)){
echo 'Combination does exists'
}
This works, but gives also a false positive if I would search for [buildingId] => 17, [typeId] => 1. How can I solve this?
edit
I would also like to know if a combination is not in the array, how can I arrange that?
if($result == false){
echo 'does not exists';
}
You can try this code:
$keyTypeExistsAndHaveSameValue = isset($array['typeId']) && $array['typeId'] === 2;
$keyBuildingExistsAndHaveSameValue = isset($array['buildingId']) && $array['buildingId'] === 2;
if($keyTypeExistsAndHaveSameValue && $keyBuildingExistsAndHaveSameValue){
echo 'Combination does exists'
}
This code check if typeId & buildingId keys exist but it also check if its values are 2 and 2.
$buildingId = 2;
$typeId = 2;
$result = false;
foreach ($array as $key => $val) {
if ($val['buildingId'] == $buildingId && $val['typeId'] == $typeId) {
$result = $key; // If you want the key in the array
$result = $val; // If you want directly the entry you're looking for
break; // So that you don't iterate through the whole array while you already have your reuslt
}
}
I think what you need is this
$keyType = array_search(1, array_column($array, 'typeId'));
$keyBuilding = array_search(17, array_column($array, 'buildingId'));
if(is_numeric($keyType)||is_numeric($keyBuilding)){
echo 'Combination does exists';
}
Now here you need or operator instead of and operator because you want either typeid = 1 exists or building id = 17 exists.
If I have understand your question correctly then you are trying to do something like this, right ?
Hope this helps!
You would need to do a foreach loop to get the actual array number, the other solution don't seems to answer what you're looking for, which is to get the index number.
I would like to search if the combination of, for example, [buildingId] => 2, [typeId] => 2 exists is array 0, 1 or 2.
EDIT: This code is just sample code to show how you would get the array index number, in a production environment you would save the matching arrays, comparison figures are not hard coded, etc...
$array = array(array('id' => 2, 'zoneId' => 2, 'buildingId' => 2, 'typeId' => 2),
array('id' => 4, 'zoneId' => 2, 'buildingId' => 2, 'typeId' => 2),
array('id' => 6, 'zoneId' => 6, 'buildingId' => 17, 'typeId' => 2));
foreach ($array as $building => $building_details)
{
if ($building_details['buildingId'] === 2 && $building_details['typeId'] === 2)
{
echo 'Array number ' . $building . ' matches criteria<br>';
}
}
Output:
Array number 0 matches criteria
Array number 1 matches criteria
You can view this snippet online here.
Struggling with concept of an associative array that maps userIDs to partIDs and re-order quantity for the part.
We have bunch of parts that I need to re-order, but I must keep track of which user needs what parts re-purchased for them. The list of UserIDs comes from one table, then the inventory_used comes from another table.
Suppose a list like this:
Example One:
UserID PartID Qty_Used
1 3 2
1 4 7
2 1 4
2 4 3
3 3 5
After creating an array with the above information, I must create a re-order form (table) for the parts. Therefore, ignoring the userID, group them by the partID, and sum up the total Qty (per part). The re-order table should look something like this:
Example Two:
PartID Qty_to_Reorder
1 4
3 7
4 10
I know I'm going to take a ton of downvotes for failing to show code, but I can't wrap my mind around this seemingly simple problem. (This is for my office, not a school project).
How do I:
(1) Structure the first array (what would the loop to create it look like?), and then
(2) Loop through that array to summarize/group partIDs => Qty for re-order report, as per 2nd example above?
For the first loop, i was thinking of something like this:
Loop through UserIDs {
Loop through PartIDs {
$arrReorder[UserID][PartID] = Qty_Used;
}
}
Is that correct? How would I loop through $arrReorder to sum-up the qty used for each partID, and get the re-order report (example 2)?
SELECT SUM(Qty_Used) AS total FROM mytable WHERE PartID=3
PS: Using PHP
<?php
$data = array();
$data[] = array("UserID" => 1, "PartID" => 3, "Qty_Used" => 2);
$data[] = array("UserID" => 1, "PartID" => 4, "Qty_Used" => 7);
$data[] = array("UserID" => 2, "PartID" => 1, "Qty_Used" => 4);
$data[] = array("UserID" => 2, "PartID" => 4, "Qty_Used" => 3);
$data[] = array("UserID" => 3, "PartID" => 3, "Qty_Used" => 5);
$PartID = 3;
$sum = 0;
foreach ($data as $arr) {
if ($arr['PartID'] == $PartID)
$sum += $arr['Qty_Used'];
}
echo $PartID."\t".$sum."\r\n";
?>
Arrays have a key and value where the value can be another array. Determine what is the key value.
I am assuming you have users consuming parts and you have to re-order the parts from your supplier. No where the user is a customer and the user has a auto re-order policy.
What triggers a reorder? If re-order quantity is 10 and user uses 1, there should be nine in stock.
Create the partsUsed array elements, This is a bit tricky:
$partsUsed[$part][] = array($qtyUsed,$user);
The reason the empty brackets [] is there is to allow duplicate part numbers in the parts used, and still key part as the key.
The value is an array to key the association between user and parts.
what you end up with is a sequentially numbered secondary key where the value is just a throw away, but allows duplicate part numbers.
$partsUsed[3][] = array(2,1);
$partsUsed[4][] = array(7,1);
$partsUsed[1][] = array(4,2);
$partsUsed[4][] = array(3,2);
$partsUsed[3][] = array(5,5);
ksort($partsUsed); // sorts key on part number
var_export($partsUsed);
Result array (var_export):
array (
1 =>
array (
0 =>
array (
0 => 4,
1 => 2,
),
),
3 =>
array (
0 =>
array (
0 => 2,
1 => 1,
),
1 =>
array (
0 => 5,
1 => 5,
),
),
4 =>
array (
0 =>
array (
0 => 7,
1 => 1,
),
1 =>
array (
0 => 3,
1 => 2,
),
),
)
Notice part 3 and 4 have two arrays.
$reorder[1] = 4 ;
$reorder[2] = 7 ;
$reorder[4] = 10 ;
var_export($reorder);
Result array:
array (
1 => 4,
2 => 7,
4 => 10,
)
Now not sure how to determine what gets reordered and how many.
I'll show how to get the values:
foreach($partsUsed as $part => $value){
foreach($value as $k => $v){
echo "Part $part: Qty:$v[0] User:$v[1]\n";
$qtyUsed[$part] += $v[1];
}
}
var_export($qtyUsed);
Outputs:
Part 1: Qty:4 User:2
Part 3: Qty:2 User:1
Part 3: Qty:5 User:3
Part 4: Qty:7 User:1
Part 4: Qty:3 User:2
$qtyUsed
array (
1 => 2,
3 => 4,
4 => 3,
)
foreach ($qtyUsed as $part => $qty){
$order[$part] = $reorder[$part];
}
var_export($order);
Result $order:
array (
1 => 4,
3 => 7,
4 => 10,
)
I've got the following array, containing ordered but non consecutive numerical keys:
Array
(
[4] => 2
[5] => 3
[6] => 1
[7] => 2
[8] => 1
[9] => 1
[10] => 1
)
I need to split the array into 2 arrays, the first array containing the keys below 5, and the other array consisting of the keys 5 and above. Please note that the keys may vary (e.g. 1,3,5,10), therefore I cannot use array_slice since I don't know the offset.
Do you know any simple function to accomplish this, without the need of using a foreach ?
Just found out array_slice has a preserve_keys parameter.
$a = [
4 => 2,
5 => 3,
6 => 1,
7 => 2,
8 => 1,
9 => 1,
10 => 1
];
$desired_slice_key = 5;
$slice_position = array_search($desired_slice_key, array_keys($a));
$a1 = array_slice($a, 0, $slice_position, true);
$a2 = array_slice($a, $slice_position, count($a), true);
you could use array_walk, passing in the arrays you wish to add the keys to by reference using the use keyword - something along the lines of this should work:
$splitArray = [1 => 2, 3 => 1, 5 => 2, 7 => 1, 9 => 3, 10 => 1];
$lt5 = [];
$gt5 = [];
array_walk($splitArray, function(&$val, $key) use (&$lt5, &$gt5) {
$key < 5 ? $lt5[] = $key : $gt5[] = $key;
});
var_dump($lt5, $gt5);
This question already has answers here:
PHP multidimensional array search by value
(23 answers)
Closed last year.
I have an array of arrays and I want to copy the first column
The data looks like this:
(0 => "homer", 1 => 1, 2 => 2, 3 => 3)
(0 => "marge", 1 => 2, 2 => 4, 3 => 8)
(0 => "bart", 1 => 6, 2 => 2, 3 => 7)
(0 => "lisa", 1 => 16, 2 => 20, 3 => 71)
Is there a PHP function (similar to array_search) which I can use to search for a name match in the first "column" ?
The data in the first column is already sorted so if I could copy "column1", I could carry out a array_search (which I assume uses a bsearch, rather than a naive element by element iteration).
My questions are:
Is there a PHP function similar to array_search, which I can use to search for matching items in the 1st column of the 2D array?
Failing that, is there a PHP function to copy the first column into a 1D array (whilst preserving order) so I can call array_search on it ?
Is there a PHP function similar to array_search, which I can use to search for matching items in the 1st column of the 2D array?
You could use array_filter
$matchedArray = array_filter($myArray, function($x) use ($nameToSearchFor) {
return $x[0] == $nameToSearchFor;
});
Then given:
$myArray = array(
array(0=>"homer", 1=> 1, 2=> 2, 3=> 3),
array(0 => "marge", 1=> 2, 2 => 4, 3=> 8),
array(0 => "bart", 1 => 6, 2 => 2, 3 => 7),
array(0 => "lisa", 1 => 16, 2 => 20, 3 => 71),
);
$nameToSearchFor = "bart";
Would produce:
$matchedArray === array(0 => "bart", 1 => 6, 2 => 2, 3 => 7);
I've used closures, that only work in PHP 5.3.0, but you use a traditional callback or create_function in older versions of php
Failing that, is there a PHP function to copy the first column into a 1D array (whilst preserving order) so I can call array_search on it ?
See deceze's first option. I see no need repeating a perfectly good answer.
$oneDarray = array_map(create_function('$a', 'return $a[0];'), $twoDarray);
Or:
foreach ($twoDarray as $values) {
if ($values[0] == 'homer') {
// found!
break;
}
}
This question came top on my Google search for array search column. It took me some time to find this better answer to the same question. By Mark M.
If you are using PHP >= 5.5, then you can use the new array_column(), >in conjunction with array_keys() and array_map().
Applied to this question, to search for "bart", it would be:
$array=array(
array(0=>"homer", 1=> 1, 2=> 2, 3=> 3),
array(0 => "marge", 1=> 2, 2 => 4, 3=> 8),
array(0 => "bart", 1 => 6, 2 => 2, 3 => 7),
array(0 => "lisa", 1 => 16, 2 => 20, 3 => 71));
$result = $array[array_search("bart",array_column($array, 0))];
print_r($result);
/* Output:
Array
(
[0] => bart
[1] => 6
[2] => 2
[3] => 7
)
*/
Run demo
PHP doesn't have a good clean way of doing this that I know of. However, you can do it yourself using a binary-search since the array is already sorted by the values in the first column of its child arrays. Here is the code to accomplish this:
<?php
// Binary Search Taken By greenmr:
// http://php.net/manual/en/function.array-search.php#89413
function array_bsearch( $needle, $haystack, $comparator ) {
$high = Count( $haystack ) -1;
$low = 0;
while ( $high >= $low ){
$probe = Floor( ( $high + $low ) / 2 );
$comparison = $comparator( $haystack[$probe], $needle );
if ( $comparison < 0 ) {
$low = $probe +1;
} elseif ( $comparison > 0 ) {
$high = $probe -1;
} else {
return $probe;
}
}
return -1;
}
// Compare the needle the first element/column
function KeyCompare( $obj, $needle) {
if ( $obj[0] < $needle ) {
return -1;
} elseif ( $obj[0] > $needle ) {
return 1;
} else {
return 0;
}
}
$arr = array(array(0=>"homer", 1=> 1, 2=> 2, 3=> 3),
array(0 => "marge", 1=> 2, 2 => 4, 3=> 8),
array(0 => "bart", 1 => 6, 2 => 2, 3 => 7),
array(0 => "lisa", 1 => 16, 2 => 20, 3 => 71));
$index = array_bsearch( 'marge', $arr, 'KeyCompare' );
// prints the array containing marge
echo print_r($arr[$index]);
?>
You could convert the array to use keys using an array_walk
$new_data = array();
array_walk($data, create_function('a','$new_data[$a[0]] = $a;'));
$search_text = 'bart';
if (array_key_exists($new_data, $search_text)) {
echo "I found '$search_text': ".print_r($new_data[$search_text], true);
}