I feel like I've done something very silly, but I can't work out what it is.
I'm running through an array of arrays generated by fgetcsv(). What I want is to split the array in two at the spot where the value in one line differs from the one in the next.
This code results in $first holding all but one of the arrays, and $second holding the last - completely ignoring the string comparison. strcmp() results in the same thing.
$csv = array();
$file = fopen('A.csv', 'r');
while (($result = fgetcsv($file)) !== false)
{
$csv[] = $result;
}
fclose($file);
array_shift($csv); //gets rid of the CSV headers
$rows = count($csv);
for ($i = 0; $i <= $rows; $i++){
if ($csv[$i][1] != $csv[$i+1][1]){
$first = array_slice($csv, 0, $i);
$second = array_slice($csv, $i);
}
}
Here's an example of the CSV file:
NAME,MATCHNAME,CHROMOSOME,START LOCATION,END LOCATION,CENTIMORGANS,MATCHING SNPS
A,person_one,2,20945970,23287731,2.48,500
A,person_one,2,233444593,234432885,1.56,500
A,person_one,4,99184637,100861136,1.24,500
A,person_two,1,154990798,157871980,2.8,700 //Here's where the new array should start
A,person_two,1,67136078,70785393,2.28,800
EDIT: My expected $first for this example would be:
Array
(
[0] => Array
(
[0] => A
[1] => person_one
[2] => 2
[3] => 20945970
[4] => 23287731
[5] => 2.48
[6] => 500
)
[1] => Array
(
[0] => A
[1] => person_one
[2] => 2
[3] => 233444593
[4] => 234432885
[5] => 1.56
[6] => 500
)
[2] => Array
(
[0] => A
[1] => person_one
[2] => 4
[3] => 99184637
[4] => 100861136
[5] => 1.24
[6] => 500
)
)
And my expected $second would be:
Array
(
[0] => Array
(
[0] => A
[1] => person_two
[2] => 1
[3] => 154990798
[4] => 157871980
[5] => 2.8
[6] => 700
)
[1] => Array
(
[0] => A
[1] => person_two
[2] => 1
[3] => 67136078
[4] => 70785393
[5] => 2.28
[6] => 800
)
)
It is doing what you want, but when it gets to the last iteration, it compares whatever's in the last line with null, so it overwrites $first and $second.
Try adding break; after the assignments to break out of the loop when the condition is met.
Related
I originally have this array
Array
(
[0] => Amministrativo ^25^9,11,2,10,18,4,7,^17,13,^0.75^0^0.25
[1] => Logico deduttive^7^^21,^0.75^0^-0.25
[2] => Situazionali^8^^20,^0.75^0^0.375
)
Using the function explode and array_diff i can get to this
Array
(
[0] => Amministrativo
[1] => 25
[2] => 9,11,2,10,18,4,7,
[3] => 17,13,
[4] => 0.75
[5] => 0
[6] => 0.25
)
Array
(
[0] => Logico deduttive
[1] => 7
[2] =>
[3] => 21,
[4] => 0.75
[5] => 0
[6] => -0.25
)
Array
(
[0] => Situazionali
[1] => 8
[2] =>
[3] => 20,
[4] => 0.75
[5] => 0
[6] => 0.375
)
but I would like to concatenate the elements of each array to get a unique array. I think I need to use the array_map function but I don't know how. This below is the result I would like to achieve
Array (
[0] => Amministrativo Logico deduttive Situazionali
[1] => 25 7 8
[2] => 9,11,2,10,18,4,7,
[3] => 17,13,21,20,
[4] => 0.75 0.75 0.75
[5] => 0 0 0
[6] => 0.25 -0.25 0.375
)
tnks
EDIT:
I tried the code that is here and it is fine.
But now I realized that there is also the problem that the arrays can be in variable number 1, 2, 3 or more and I can't know it before, I should adapt this code
$result = array_map(function ($item1, $item2,$item3) {
return "$item1 $item2 $item3";
}, $test[0], $test[1],$test[2]);
The lines of the original array are split with explode. The result is a two-dimensional array. This is transposed (swapping rows and columns). Then the lines are reassembled with implode.
function array_transpose(array $a) {
$r = array();
foreach($a as $keyRow => $subArr) {
foreach($subArr as $keyCol => $value) $r[$keyCol][$keyRow] = $value;
}
return $r;
}
$arr = [
'Amministrativo ^25^9,11,2,10,18,4,7,^17,13,^0.75^0^0.25',
'Logico deduttive^7^^21,^0.75^0^-0.25',
'Situazionali^8^^20,^0.75^0^0.375',
];
foreach($arr as $i => $row){
$arr[$i] = explode('^',$row);
}
$arr = array_transpose($arr);
foreach($arr as $i => $row){
$arr[$i] = implode(' ',$row);
}
var_export($arr);
Demo: https://3v4l.org/IdsDh
In my PHP file, I'm receiving a total of 4 variables $data, $date, $shift and $val1.
$data is an array and the other 3 are date and 2 strings obtained through AJAX with no problem.
What I'm trying to do is to insert these 3 values inside my $data variable.
I tried using array merge, and a For each loop with multiple instances but no luck so far.
I obtained my variables like this:
if (isset($_POST['date'])){
$date = $_POST['date'];
$date = json_encode($date);
$date = json_decode($date);
}
if (isset($_POST['shift'])){
$shift = $_POST['shift'];
$shift = json_encode($shift);
$shift = json_decode($shift);
}
if (isset($_POST['val1'])){
$val1 = $_POST['val1'];
$val1 = json_encode($val1);
$val1 = json_decode($val1);
}
if (isset($_POST['data'])){
$dat = $_POST['data'];
$data = json_decode($dat, true);
}
$values = array($date,$shift,$val1);
$r = (array_merge($data, $values));
My data array looks something like this:
Array (
[0] => Array (
[data] => Array (
[0] => Array (
[0] => 1
[1] => 2
[2] => 3
[3] => 0
[4] => Mat1
[5] => Box1
[6] => 100
[7] => 100
[8] => Piece1
[9] => Loc1
[10] => Mach1
[11] => 1000
[12] => Accepted
)
)
)
[1] => 2019-04-09
[2] => First
[3] => Value1
)
But what I want to achieve is this:
Array (
[0] => Array (
[data] => Array (
[0] => Array (
[0] => 1
[1] => 2
[2] => 3
[3] => 0
[4] => Mat1
[5] => Box1
[6] => 100
[7] => 100
[8] => Piece 1
[9] => Suc1
[10] => Mach1
[11] => 1000
[12] => Accepted
[13] => 2019-04-09
[14] => First
[15] => Value1
)
)
)
)
What am I doing wrong? Or How can I achieve what I'm trying to do?
Edit: Since I can get more than one array at my array, something like this
Array (
[0] => Array (
[data] => Array (
[0] => Array (...)
[1] => Array (...)
[2] => Array (...)
[3] => Array (...)
)
)
)
I just added this code to #HelgeB answer, I'm leaving it here in case someone might need it in the future.
$count = count($data[0]['data']);
for ($i=0; $i < $count ; $i++) {
$data[0]['data'][$i][] = $date;
$data[0]['data'][$i][] = $shift;
$data[0]['data'][$i][] = $val1;
}
As far as I can see from your merged output, your $data array structure is $data[0]['data'][0] = [1,2,3,...,'Accepted'].
So in my opinion you need to insert the values exactly on the level $data[0]['data'][0] to obtain your result.
The simplest way to achieve this would be:
$data[0]['data'][0][] = $date;
$data[0]['data'][0][] = $shift;
$data[0]['data'][0][] = $val1;
If you want to use your merge approach you need to merge on the correct level like this:
$r = [0 => ['data' => [0 => (array_merge($data[0]['data'][0], $values))]]];
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
)
)
I've some problem to construct an array.
Array A:
Array
(
[0] => 2015-09-13
[1] => 2015-09-14
[2] => 2015-09-15
[3] => 2015-09-16
[4] => 2015-09-17
[5] => 2015-09-18
[6] => 2015-09-19
)
Array B:
Array
(
[0] => 1
[1] => 8
)
Array C:
Array
(
[0] => Leaves-19
[1] => Shifts-18
[2] => Shifts-18
[3] => Shifts-18
[4] => Shifts-18
[5] => Shifts-18
[6] => Leaves-19
[7] => Leaves-19
[8] => Shifts-12
[9] => Shifts-12
[10] => Shifts-12
[11] => Shifts-12
[12] => Shifts-12
[13] => Leaves-19
)
Desired final output:
Array
(
[0] => 2015-09-13|1|Leaves-19
[1] => 2015-09-14|1|Shifts-18
[2] => 2015-09-15|1|Shifts-18
[3] => 2015-09-16|1|Shifts-18
[4] => 2015-09-17|1|Shifts-18
[5] => 2015-09-18|1|Shifts-18
[6] => 2015-09-19|1|Leaves-19
[7] => 2015-09-13|8|Leaves-19
[8] => 2015-09-14|8|Shifts-12
[9] => 2015-09-15|8|Shifts-12
[10] => 2015-09-16|8|Shifts-12
[11] => 2015-09-17|8|Shifts-12
[12] => 2015-09-18|8|Shifts-12
[13] => 2015-09-19|8|Leaves-19
)
I'm lost in for and foreach.
Here's the logic:
1st parameter is a date and it come's form array B. It is repeat
after 6 entries.
2nd parameter is the user id. It changes after 6 entries and pass to the next id.
3rd parameter is an entry of array B.
Oter informations:
The arrays don't have the same length.
Array A, counts 6 entries.
Array B, counts a random entries.
Array C, is Array A x 2.
I already tried to make a for for my array B and after a foreach in array A, but it wasn't functional.
I do not know where I need to start.
Hope I will have any help or cue.
Thanks a lot.
you can use modulus operator
$OutputArray = Array();
for($i=0; $i < max(count($a1),count($a2),count($a3)); $i++){
array_push($OutputArray, $a1[ $i % count($a1) ] . "|" .
$a2[ $i % count($a2) ] . "|" . $a3[ $i % count($a3) ]);
}
print_r($OutputArray);
you get:
Array
(
[0] => 2015-09-13|1|Leaves-19
[1] => 2015-09-14|8|Shifts-18
[2] => 2015-09-15|1|Shifts-18
[3] => 2015-09-16|8|Shifts-18
[4] => 2015-09-17|1|Shifts-18
[5] => 2015-09-18|8|Shifts-18
[6] => 2015-09-19|1|Leaves-19
[7] => 2015-09-13|8|Leaves-19
[8] => 2015-09-14|1|Shifts-12
[9] => 2015-09-15|8|Shifts-12
[10] => 2015-09-16|1|Shifts-12
[11] => 2015-09-17|8|Shifts-12
[12] => 2015-09-18|1|Shifts-12
[13] => 2015-09-19|8|Leaves-19
)
if you want in order (expected):
$OutputArray = Array();
$max = max(count($a1),count($a2),count($a3));
for($i=0; $i < $max; $i++){
array_push($OutputArray, $a1[$i%count($a1)] . "|" .
$a2[ $i*count($a2) / $max ] . "|" . $a3[$i%count($a3)]);
}
print_r($OutputArray);
you get:
Array
(
[0] => 2015-09-13|1|Leaves-19
[1] => 2015-09-14|1|Shifts-18
[2] => 2015-09-15|1|Shifts-18
[3] => 2015-09-16|1|Shifts-18
[4] => 2015-09-17|1|Shifts-18
[5] => 2015-09-18|1|Shifts-18
[6] => 2015-09-19|1|Leaves-19
[7] => 2015-09-13|8|Leaves-19
[8] => 2015-09-14|8|Shifts-12
[9] => 2015-09-15|8|Shifts-12
[10] => 2015-09-16|8|Shifts-12
[11] => 2015-09-17|8|Shifts-12
[12] => 2015-09-18|8|Shifts-12
[13] => 2015-09-19|8|Leaves-19
)
Try this, it iterates over the biggest array and condition the counting of the minor ones to its desired listing behavior.
<?php
$arrA = ['2015-09-13','2015-09-14','2015-09-15','2015-09-16',
'2015-09-17','2015-09-18','2015-09-19'];
$arrB = [1,8];
$arrC = ['Leaves-19','Shifts-18','Shifts-18','Shifts-18','Shifts-18','Shifts-18',
'Leaves-19','Leaves-19','Shifts-12','Shifts-12','Shifts-12','Shifts-12','Shifts-12',
'Leaves-19'];
$a = $b = 0;
for ($c = 0; $c < count($arrC); $c++) {
$arrC[$c] = $arrA[$a].'|'.$arrB[$b].'|'.$arrC[$c];
$a++;
if ($a == count($arrA)) {
$a = 0;
$b++;
}
};
echo "<pre>";
print_r($arrC);
OUTPUT:
Array
(
[0] => 2015-09-13|1|Leaves-19
[1] => 2015-09-14|1|Shifts-18
[2] => 2015-09-15|1|Shifts-18
[3] => 2015-09-16|1|Shifts-18
[4] => 2015-09-17|1|Shifts-18
[5] => 2015-09-18|1|Shifts-18
[6] => 2015-09-19|1|Leaves-19
[7] => 2015-09-13|8|Leaves-19
[8] => 2015-09-14|8|Shifts-12
[9] => 2015-09-15|8|Shifts-12
[10] => 2015-09-16|8|Shifts-12
[11] => 2015-09-17|8|Shifts-12
[12] => 2015-09-18|8|Shifts-12
[13] => 2015-09-19|8|Leaves-19
)
My version:
$arrayA = array('2015-09-13','2015-09-14','2015-09-15','2015-09-16','2015-09-17','2015-09-18','2015-09-19');
$arrayB = array(1,8);
$arrayC = array('Leaves-19','Leaves-18','Leaves-17','Leaves-16','Leaves-15','Leaves-14','Leaves-13','Leaves-12','Leaves-11','Leaves-10','Leaves-9','Leaves-8','Leaves-7','leaves-6');
$output = array();
$count = 0;
foreach($arrayB as $arrayBElement){
foreach($arrayA as $arrayAElement){
$output[] = $arrayC[$count] . '|' . $arrayAElement . '|' . $arrayBElement;
$count++;
}
}
var_dump($output);
E: removed erroneous count
This stinks of a homework problem so I'm going to answer in pseudocode so hopefully you can apply some hints and come to the solution yourself.
It appears that maybe Array B ([1,8]) is a list of indexes at which to start printing out the next index. Your own statement (2nd parameter is the user id. It changes after 6 entries and pass to the next id.) is not accurate based on your desired final output:
[6] => 2015-09-19|1|Leaves-19
[7] => 2015-09-13|8|Leaves-19
This moves to the next id at index 7 (count 8) not index 6 (count 7, or one after 6 entries).
So My pseudo solution would be this:
Create a new array by repeating Array A until it matches the length of Array C
Append Array B to Array A by finding the element of Array B that is equal to or less than (1+index):
0 => '1', 1 => '1' ... 7 => '8'
Concatenate Array C to every array with index parity (eg. newArray[ 0 ] . ArrayC[ 0 ])
This gives you the final output you desire.
try this code, I have named your 3 arrays as $arrA, $arrB and $arrC
$arrA = Array(
'2015-09-13',
'2015-09-14',
'2015-09-15',
'2015-09-16',
'2015-09-17',
'2015-09-18',
'2015-09-19'
);
$arrB = array(1,8);
$arrC = array(
'Leaves-19',
'Shifts-18',
'Shifts-18',
'Shifts-18',
'Shifts-18',
'Shifts-18',
'Leaves-19',
'Leaves-19',
'Shifts-12',
'Shifts-12',
'Shifts-12',
'Shifts-12',
'Shifts-12',
'Leaves-19'
);
$output = array();
$indx = 0;
foreach($arrB as $b){
foreach($arrA as $a){
$output[] = $a.'|'.$b.'|'.$arrC[$indx];
$indx++;/*new line addded*/
}
//$indx++;/*remove this line from here*/
}
echo "<pre>";
print_r($output);
echo "</pre>";
With different sizes try guess maxlength
//Create arrays
var Adates= ["2015-09-13", "2015-09-14", "2015-09-15"];
var Bnums= ["1", "2", "3"];
var Cnums= ["Leaves-19", "Shifts-18", "Shifts-18"];
//get size
var maxLenght=0;
if(Adates.length>maxLenght) maxLenght=Adates.length;
if(Bnums.length>maxLenght) maxLenght=Bnums.length;
if(Cnums.length>maxLenght) maxLenght=Cnums.length;
//merge and populate
var OutputArray;
for (i = 0; i < maxLenght; i++) {
OutputArray[i]=Adates[i]+"|"+Bnums[i]+"|"+Cnums[i];
}
Hello I'm trying to solve the following issue. I have some code which is self explanatory but I need to add a couple of lines to it
I would like filter the lower value arrays defined by the key value (in this case [2]) via the key value [1]. So if I have 3 arrays which contain key [1] with a value 100, then the arrays should be filtered via key [2].
Example of my code so far:
foreach($data as $line) {
if(substr($line,0,1)=="A") {
if(!$first) {
$parts = explode(chr(9), $line);
list($num1, $num2) = explode('_', $parts[1]); //code comes first / tested and works
$parts[2] = isset($num2) ? $num2 : $parts[2]; //it replaces key[2] with _* (1,2,3)
//then this will follow
$pos = strpos($parts[1], '_'); // this will remove all _* from key [1] if they exist
if($pos !== false) $parts[1] = substr($parts[1], 0, $pos); // tested and works
//echo "<pre>"; print_r($parts); echo "</pre>";
//need code to filter the arrays defined by key [1] via key [2] here?
So for example if I have multiple arrays after my piece of code like this:
Array
(
[0] => A
[1] => 100
[2] => 1
[3] => 1184
[4] => 0
)
Array
(
[0] => A
[1] => 100
[2] => 2
[3] => 1185
[4] => 0
)
Array
(
[0] => A
[1] => 100
[2] => 3
[3] => 1186
[4] => 0
)
Array
(
[0] => A
[1] => 101
[2] => 1
[3] => 1187
[4] => 0
)
Array
(
[0] => A
[1] => 101
[2] => 2
[3] => 1188
[4] => 0
)
Array
(
[0] => A
[1] => 302
[2] => 0
[3] => 1161
[4] => 0
)
After some code to filter the arrays, the final example result will be:
Array
(
[0] => A
[1] => 100
[2] => 3
[3] => 1186
[4] => 0
)
Array
(
[0] => A
[1] => 101
[2] => 2
[3] => 1188
[4] => 0
)
Array
(
[0] => A
[1] => 302
[2] => 0
[3] => 1161
[4] => 0
)
Please I could do with some help on this it only needs a couple of lines, I'm not a programmer but I'd like to finish this project.
Try this :
$array = array("A", "100_1", 0, 1184, 0);
$array = array_map(
function($str) {
return preg_replace_callback('/([\d]+)\_([1-3])/', function($matches){ return $matches[1] + $matches[2]-1;}, $str);
},
$array
);
print_r($array)
Try this:
$part = array();
foreach ($parts as $key => $value) {
if (isset($part[$value[1]])) {
if ($parts[$part[$value[1]]][0][2] < $value[0][2]) {
$part[$value[1]] = $key;
}
} else {
$part[$value[1]] = $key;
//echo "<pre>"; print_r($part); echo "</pre>";
}
}
I change the answer because it was not what I'm looking for but this is.