PHP count line/row on text file based on value column - php

Continuing on my previous question.
I have text log file called reject. You can see it here
As you can see there are 4 steps on tab called:
1. Battery level
2. Piezo sound level
3. Left D3 (Ch 3) light intensity
4. Right D2 (Ch 1) light intensity
Now I want to count every row with condition:
Which column(Steps) value is filled then count it.
Example: on row 1, We can see the value 0 (any value) is on step Piezo sound level. Then count it.
So finally I can know how many quantity Reject Process.
Battery level = x quantity
Piezo sound level = x quantity
Left D3 (Ch 3) light intensity = x quantity
Right D2 (Ch 1) light intensity = x quantity
The PHP Code:
$fromDateTime = new DateTime('Wed, Sep 19 2018 08:00:00');
$toDateTime = new DateTime('Wed, Sep 19 2018 19:59:00');
$file = file_get_contents('reject.txt');
$lines = explode("\n",$file);
// counter
$rowsintimespan = 0;
// Do Line-By-Line starting by Line 16 (Array Index 15)
for($i = 15; $i < count($lines); $i++) {
// if the file is "Tue, Sep 18<tab>2018<tab>23:59:53<tab>"
$dateobj = DateTime::createFromFormat("???,?M?d??Y?H:i:s+", $lines[$i]);
// check if date is in your Timespan
if($dateobj < $toDateTime && $dateobj > $fromDateTime) {
$rowsintimespan++; // count if in timespan
}
}
// Debug-Output
echo $rowsintimespan;
UPDATE
I need to read the last column value, Example: if the value of row is on column Left D3 then count it. If the value of row is on column Piezo then count it.

if you're ok with writing down your columns as keys then this should work as you described:
$fromDateTime = new DateTime('Wed, Sep 19 2018 08:00:00');
$toDateTime = new DateTime('Wed, Sep 19 2018 19:59:00');
$file = file_get_contents('Reject.txt');
$lines = explode("\n", $file);
// counter
$rowsintimespan = 0;
// keys should correspond to columns
$keys = [
'date',
'time',
'battery',
'piezo',
'leftD3',
'rightD2'
];
$values = array_fill(0, count($keys), 0);
$values = array_combine($keys, $values);
// Do Line-By-Line starting by Line 16 (Array Index 15)
for ($i = 11; $i < count($lines); $i++) {
// if the file is "Tue, Sep 18<tab>2018<tab>23:59:53<tab>"
$dateobj = DateTime::createFromFormat("???,?M?d??Y?H:i:s+", $lines[$i]);
// check if date is in your Timespan
if ($dateobj < $toDateTime && $dateobj > $fromDateTime) {
$rowsintimespan++; // count if in timespan
// get line elements
$lineContent = explode("\t", $lines[$i]);
// loop through line elements and count them
$x = 0;
for ($j = 0; $j < count($keys); $j++) {
if (!isset($lineContent[$j])) {
continue;
}
// remember position of last not empty column
if (trim($lineContent[$j]) != '') {
$x = $j;
}
}
if ($x > 0) {
$values[$keys[$x]]++;
}
}
}
// Debug-Output
echo $rowsintimespan;
// Output every column
echo '<pre>';
print_r($values);
This will print out:
Array
(
[date] => 0
[time] => 0
[battery] => 4
[piezo] => 31
[leftD3] => 17
[rightD2] => 1
)

Just split your row by your tabs and check for !empty();
//Set Time-Span
$fromDateTime = new DateTime('Wed, Sep 19 2018 00:00:00');
$toDateTime = new DateTime('Wed, Sep 19 2018 17:00:00');
// Load File
$file = file_get_contents('Reject.txt');
// Split by lines
$lines = explode("\n",$file);
// counter
$rowsintimespan = 0;
$rowswithbattery = 0;
// Do Line-By-Line starting by Line 16 (Array Index 15)
for($i = 15; $i < count($lines); $i++) {
// if the file is "Tue,<space>Sep<space>18<space><space>2018<tab>23:59:53<tab>"
$dateobj = DateTime::createFromFormat("???, M d?Y?H:i:s+", $lines[$i]);
// check if date is in your Timespan
if($dateobj < $toDateTime && $dateobj > $fromDateTime) {
$rowsintimespan++; // count if in timespan
$cols = explode("\t",$lines[$i]);
// 0 = Date, 1 = Time, 2 = Battery Level, 3 = Piezo, 4 = left, 5 = Right
// Count Battery-Values
if (!empty($cols[2])) {
$rowswithbattery++;
}
}
}
// Debug-Output
echo 'In Timespan: '.$rowsintimespan."\n";
echo 'Rows With Battery: '.$rowswithbattery
Produces:
In Timespan: 84
Rows With Battery: 84
Full Example with all your columns: https://ideone.com/VAQH7h
Also you could iterate over every header and create a neat array as I showed in https://ideone.com/YUU1jP
// Split by lines
$lines = explode("\n", $file);
$header = explode("\t", $lines[9]);
// counter
$rowsintimespan = 0;
$counter = Array();
// Create an entry for every header and trim it to lose additional whitespaces
foreach($header as $index => $head){
$counter[rtrim($head)] = 0;
}
// Do Line-By-Line starting by Line 16 (Array Index 15)
for($i = 11; $i < count($lines); $i++) {
// the file is "Tue,<space>Sep<space>18<space><space>2018<tab>23:59:53<tab>"
$dateobj = DateTime::createFromFormat("???, M d Y?H:i:s+", $lines[$i]);
// check if date is in your Timespan
if($dateobj < $toDateTime && $dateobj > $fromDateTime) {
$rowsintimespan++; // count if in timespan
$cols = explode("\t",$lines[$i]);
// 0 = Date, 1 = Time, 2 = Battery Level, 3 = Piezo, 4 = left, 5 = Right
// Count Battery-Values
foreach($header as $index => $head){
// For every header check if col is empty
$counter[rtrim($head)] += empty($cols[$index]) ? 0 : 1;
}
}
}
// Debug-Output
echo 'In Timespan: '.$rowsintimespan."\n";
var_dump($counter);
Update to match the updated question:
Then just do some simple math.
Theory: if you have 80 set columns with battery, and 20 with set piezo, you can substract the 20 piezo counter from your 80 battery counter and then you know how many last battery-columns you have and how many last piezo columns.
Thus:
$lastwithright = $rowswithright;
$lastwithleft = $rowswithleft - $rowswithright;
$lastwithpiezo = $rowswithpiezo - $rowswithleft;
$lastwithbattery = $rowswithbattery - $rowswithpiezo;

Related

Pairwise function different calculation

i have this function:
function pairwiseDifference($arry)
{
$n = count($arry) - 1; // you can add the -1 here
$diff = 0;
$result = array();
for ($i = 0; $i < $n; $i++)
{
// absolute difference between
// consecutive numbers
$diff = abs($arry[$i] - $arry[$i + 1]);
echo $diff." ";
array_push($result, $diff); // use array_push() to add new items to an array
}
return $result; // return the result array
}
$arry = array(20,10,10,50);
echo "<br> Percent of commisions are: ";
// this echos 10,0,40 and assigns whatever your function returns
// to the variable $diffArray
$diffArray = pairwiseDifference($arry);
The problem are that im not expecting this output
becouse first number of array (20) is my commission
and the other numbers are my parents commission (10,10,50).
So basically i need to output like this: (0,0,30)
becouse i take 20 of commission,
first parent not take nothing becouse are less of my commission (10)
second parent not take nothing becouse are less of my commission (10)
and only last parent take 30 becouse are greater than my commission (50 - 20 my commission).
Thanks in advance
Since your first element of the array is your commission and the others are the the commissions of parents, and since it seems that you don't want to include your commission in the result array, you can do something like this:
function pairwiseDifference($arry)
{
$n = count($arry);
$diff = 0;
$result = array();
$myComm = $arry[0]; // your commision
for ($i = 1; $i < $n; $i++)
{
$diff = 0; // set $diff to 0 as default
if($myComm < $arry[$i]) // if your commision < parent commision
$diff = $arry[$i] - $myComm;
echo $diff." ";
array_push($result, $diff);
}
return $result;
}
$arry = array(20,10,10,50);
echo "<br> Percent of commisions are: ";
$diffArray = pairwiseDifference($arry);
echo $diffArray[0]; // prints 0
echo $diffArray[1]; // prints 0
echo $diffArray[2]; // prinst 30
To tweak the logic according to your code, there would be only 3 modifications.
Create a $max variable and assign it the value of $arry[0].
Make difference as 0 if current max is greater than current one, else take the difference.
Calculate the new max again using max() function.
Snippet:
<?php
function pairwiseDifference($arry)
{
$n = count($arry) - 1; // you can add the -1 here
$diff = 0;
$result = array();
$max = $arry[0]; // new addition
for ($i = 1; $i <= $n; $i++) // new modification <= n instead of < n
{
// absolute difference between
// consecutive numbers
$diff = $max < $arry[$i] ? $arry[$i] - $max : 0; // new modification
$max = max($max, $arry[$i]); // new modification
echo $diff." ";
array_push($result, $diff); // use array_push() to add new items to an array
}
return $result; // return the result array
}
$arry = array(20,10,10,50);
echo "<br> Percent of commisions are: ";
// this echos 10,0,40 and assigns whatever your function returns
// to the variable $diffArray
$diffArray = pairwiseDifference($arry);

data fetch according to range as compare to user data in PHP

This is MY DB Table:
id target_download date
1 10 2019-06-18
2 20 2019-06-18
3 30 2019-06-18
4 40 2019-06-18
If suppose user download = 15 it will count in 10 to 19 range and get first-row id = 1
If suppose user download = 25 it will count in 20 to 29 range and get second-row id = 2
So get data according to user download and range.
I think you understand my question.
I Try This:
$=i;
foreach ($datas as $key=>$val){
if($datas[$i]['targer_download'] >= $user_download && $datas[$i+1]['targer_download'] < $user_download){
}
}
Try this
$data[]['target_download'] = 10;
$data[]['target_download'] = 20;
$data[]['target_download'] = 30;
$data[]['target_download'] = 40;
$user_download = 15;
foreach($data as $key => $val) {
if($user_download >= $val['target_download'] && $user_download < $data[++$key]['target_download']) {
//Do your stuff
echo "Range is ".$val['target_download'];
}
}
I am assuming that you will be getting your data from DB with a numeric array.
EDIT
Other solution
$arr = array(10, 20, 30, 40);
function getClosest($search, $arr) {
$a = null;
foreach ($arr as $i) {
$a = $search >= $i ? $i : $a;
}
return $a===null ? 0:$a;
}
echo $v = getClosest(15, $arr);

Can someone help me return a value?

I have created a loop which returns a random number between two values. Cool.
But now I want the script to return the following value too: The number of unique numbers between two similar numbers.
Example:
4
5
8
22
45
3
85
44
4
55
15
23
As you see there is a double which is the four and there are 7 numbers inbetween. So I would like the script to echo these numbers two so in this case it should echo 7 but if there are more doubles in the list it should echo all the numbers between certain doubles.
This is what I have:
for ($x = 0; $x <= 100; $x++) {
$min=0;
$max=50;
echo rand($min,$max);
echo "<br>";
}
Can someone help me or guide me? I'm learning :)
Thanks!
So You need to seperate script for three parts:
getting randoms and save them to array (name it 'result'),
analyze them,
print (echo) results
Simply - instead of printing every step of loop, save them to array(), exit loop, analyze every item with other, example:
take i element of list
check is i+j element is the same
if is it the same - save j-i to second array() (name it 'ranges')
And after this, print two arrays (named by me as 'result' and 'ranges')
UPDATE:
Here's solution, hope You enjoy:
$result = array(); #variable is set as array object
$ranges = array(); #same
# 1st part - collecting random numbers
for ($x = 0; $x < 20; $x++)
{
$min=0;
$max=50;
$result[] = rand($min,$max); #here's putting random number to array
}
$result_size = count($result); #variable which is containg size of $result array
# 2nd part - getting ranges between values
for ($i = 0; $i < $result_size; $i++)
{
for ($j = 0; $j < $result_size; $j++)
{
if($i == $j) continue; # we don't want to compare numbers with itself,so miss it and continue
else if($result[$i] == $result[$j])
{
$range = $i - $j; # get range beetwen numbers
if($range > 0 ) # this is for miss double results like 14 and -14 for same comparing
{
$ranges[$result[$i]] = $range;
}
}
}
}
#3rd part - priting results
echo("RANDOM NUMBERS:<br>");
foreach($result as $number)
{
echo ("$number ");
}
echo("<br><br>RANGES BETWEEN SAME VALUES:<br>");
foreach($ranges as $number => $range)
{
echo ("For numbers: $number range is: $range<br>");
}
Here's sample of echo ($x is set as 20):
RANDOM NUMBERS:
6 40 6 29 43 32 17 44 48 21 40 2 33 47 42 3 22 26 39 46
RANGES BETWEEN SAME VALUES:
For numbers: 6 range is: 2
For numbers: 40 range is: 9
Here is your fish:
Put the rand into an array $list = array(); and $list[] = rand($min,$max); then process the array with two for loops.
$min=0;
$max=50;
$list = array();
for ($x = 0; $x <= 100; ++$x) {
$list[] = rand($min,$max);
}
print "<pre>";print_r($list);print "</pre>";
$ranges = array();
$count = count($list);
for ($i = 0; $i < $count; ++$i) {
$a = $list[$i];
for ($j = $i+1; $j < $count; ++$j) {
$b = $list[$j];
if($a == $b) {
$ranges[] = $j-$i;
}
}
}
print "<pre>";print_r($ranges);print "</pre>";

Add Date/Mont/Year if is missing to array

I want to have an array which is always ascending without a gap between days, months or years. So, at the end I want to have something like this for example 2012, 2013, 2014, 2015, 2016.
Example arrays:
$data = [2012, 2013, 2015, 2017]
$anzeige = [1, 5, 8, 3]
Want I want to have at the end:
$data = [2012, 2013, 2014, 2015, 2016, 2017]
$anzeige = [1, 5, 0, 8, 0, 3]
But sometimes there are no data avaiveble for some days, months or years. So, I have a gap. I want to close this gap and add the following day, month or year to the array and it should remain ascending.
This is my code so far:
private function fixDates($daten, $anzahl){
$tmpArrayDaten = array();
$tmpArrayAnzahl = array();
$this->logger->lwrite("Fix Data");
for ($i=0; $i < sizeof($daten) - 1 ; $i++) {
if(($i + 1) == sizeof($daten)){
return array(array("daten" => $daten), array("anzahl" => $anzahl));
}
if(!(($daten[$i] + 1) == ($daten[$i + 1]))){
$this->logger->lwrite(($daten[$i] + 1) . " != " . ($daten[$i + 1]));
for($j = 0; $j < $i; $j++){
$tmpArrayDaten[] = $daten[$j];
$tmpArrayAnzahl[] = $anzahl[$j];
}
$tmpArrayDaten[] = $daten[$i] + 1;
$tmpArrayAnzahl[] = 0;
for($j = $i; $j < (sizeof($daten) + 1); $j++){
$tmpArrayDaten[] = $daten[$j];
$tmpArrayAnzahl[] = $anzahl[$j];
}
$this->logger->lwrite(var_export($tmpArrayDaten));
$this->logger->lwrite(var_export($tmpArrayAnzahl));
$this->fixDates($tmpArrayDaten, $tmpArrayAnzahl);
}
}
return array(array("daten" => $daten), array("anzahl" => $anzahl));
}
The $anzahl array contains the value for the day, month or year at the same index in the $daten array. And no, I do not want to have them in one array because I am going to create one array at the end to send it via json_encode() to JavaScript.
However, I cannot find my failure in my code... It never stops. It doesn't stop to add "placeholder" if there is a gap...
Do you may have an idea how to fix that?
Kind regards
$data = [2012, 2013, 2016, 2017, 2020];
$anzeige = [1, 5, 8, 3, 10];
list($new_data, $new_clicks) = fillGaps($data, $anzeige);
print_r($new_data);
print_r($new_clicks);
function fillGaps($data, $clicks) {
// assume the first element is right
$fixed_data = array($data[0]);
$fixed_clicks = array($clicks[0]);
for ($i = 1; $i < count($data); $i++) {
// if there is a gap, fill it (add 0s to corresponding array)
while (end($fixed_data)+1 != $data[$i]) {
$fixed_data[] = end($fixed_data) + 1;
$fixed_clicks[] = 0;
}
// add the data which exists after gap
$fixed_data[] = $data[$i];
$fixed_clicks[] = $clicks[$i];
}
return array($fixed_data, $fixed_clicks);
}

Possible combinations of binary

The problem statement is as following:
A particular kind of coding which we will refer to as "MysteryCode" is a binary system of encoding in which two successive values, differ at exactly one bit, i.e. the Hamming Distance between successive entities is 1. This kind of encoding is popularly used in Digital Communication systems for the purpose of error correction.
LetMysteryCodes(N)represent the MysteryCode list for N-bits.
MysteryCodes(1) = 0, 1 (list for 1-bitcodes,in this order)
MysteryCodes(2) = 00, 01, 11, 10 (list for 2-bitcodes,in this order)
MysteryCodes(3) =000, 001, 011, 010,110, 111, 101, 100 (list for 3-bitcodes,in this order)
There is a technique by which the list of (N+1) bitcodescan be generated from (N)-bitcodes.
Take the list of N bitcodesin the given order and call itList-N
Reverse the above list (List-N), and name the new reflected list: Reflected-List-N
Prefix each member of the original list (List-N) with 0 and call this new list 'A'
Prefix each member of the new list (Reflected-List-N) with 1 and call this new list 'B'
The list ofcodeswith N+1 bits is the concatenation of Lists A and B.
A Demonstration of the above steps: Generating the list of 3-bitMysteryCodesfrom 2-BitMysteryCodes
2-bit list ofcodes:00, 01, 11, 10
Reverse/Reflect the above list:10, 11, 01, 00
Prefix Old Entries with 0:000, 001, 011, 010
Prefix Reflected List with 1:110, 111, 101, 100
Concatenate the lists obtained in the last two steps:000, 001, 011, 010, 110, 111, 101, 100
Your Task
Your task is to display the last N "MysteryCodes" from the list of MysteryCodes for N-bits. If possible, try to identify a way in which this list can be generated in a more efficient way, than iterating through all the generation steps mentioned above.
More efficient or optimized solutions will receive higher credit.
Input Format
A single integer N.
Output Format
N lines, each of them with a binary number of N-bits. These are the last N elements in the list ofMysteryCodesfor N-bits.
Input Constraints 1 = N = 65
Sample Input 1
1
Sample Output 1
1
Explanation for Sample 1
Since N = 1, this is the (one) last element in the list ofMysteryCodesof 1-bit length.
Sample Input 2
2
Sample Output 2
11
10
Explanation for Sample 2 Since N = 2, these are the two last elements in the list ofMysteryCodesof 2-bit length.
Sample Input 3
3
Sample Output 3
111
101
100
$listN = 25;
$bits = array('0','1');
//check if input is valid or not
if(!is_int($listN))
{
echo "Input must be numeric!";
}
if($listN >= 1 && $listN <=65){
if($listN == 1){
echo '1'; exit;
}
ini_set('memory_limit', -1);
for($i=1; $i<=($listN - 1); $i++){
$reverseBits = array_reverse($bits);
$prefixBit = preg_filter('/^/', '0', $bits);
$prefixReverseBits = preg_filter('/^/', '1', $reverseBits);
$bits = array_merge($prefixBit, $prefixReverseBits);
unset($prefixBit, $prefixReverseBits, $reverseBits);
}
$finalBits = array_slice($bits, -$listN);
foreach($finalBits as $k=>$v){
echo $v."\n";
}
}
else{
echo "Invalid input!";
}
I have tried above solution, but didnt worked for input greater than 20.
for eg. If the input is 21, I got "Couldnt allocate memory" error.
It will be great if somebody figure out the optimized solutions...
The numbers follow a pattern which I transformed to below code.
Say given number is N
then create a N x N matrix and fill it's first column with 1's
and all other cells with 0's
Start from rightmost column uptil 2nd column.
For any column X start from bottom-most row and fill values like below:
Fill 2^(N - X + 1)/2 rows with 0's.
Fill 2^(N - X + 1) rows with 1's and then 0's alternatively.
Repeat step 2 till we reach topmost row.
Print the N x N matrix by joining the values in each row.
<?php
$listN = 3;
$output = [];
for ($i = 0; $i < $listN; $i++) {
$output[$i] = [];
for ($j = 0; $j < $listN; $j++) {
$output[$i][$j] = 0;
}
}
$output[$listN - 1][0] = 1;
for ($column = 1; $column < $listN; $column++) {
$zeroFlag = false;
for ($row = $listN - 1; $row >= 0;) {
$oneZero = 1;
if (!$zeroFlag) {
for ($k = 1; $k <= pow(2, $column) / 2 && $row >= 0; $k++) {
$output[$row][$listN - $column] = 0;
$row--;
$zeroFlag = true;
}
}
for ($k = 1; $k <= pow(2, $column) && $row >= 0; $k++) {
$output[$row][$listN - $column] = $oneZero;
$row--;
}
$oneZero = 0;
for ($k = 1; $k <= pow(2, $column) && $row >= 0; $k++) {
$output[$row][$listN - $column] = $oneZero;
$row--;
}
}
}
for ($i = 0; $i < $listN; $i++) {
$output[$i][0] = 1;
}
for ($i = 0; $i < $listN; $i++) {
print(join('', $output[$i]));
print("\n");
}

Categories