Recently I was practicing problems in Hackearth and I was unable to scan tab-separated values.
Ex(Inputs): 12 3 6 1
The input is treated as a file, it seems, because fscanf is used to read it.
I was trying to scan it using while loop like this:
$arr = [];
$i = 0;
while($i < 4){
fscanf(STDIN, "%s\t", $a);
$arr[] = $a;
$i++;
}
But when I am printing $arr like:
print_r($arr);
It shows like this:
Array
(
[0] => 12
[1] => 12
[2] => 12
[3] => 12
)
I checked this problem but unable to solve my problem.
How can I scan all the numbers using a loop and put it in an array?
According to the documentation:
Each call to fscanf() reads one line from the file.
So you can't call fscanf() in a loop to read each number from the same line. The second iteration tries to read the next line, but there isn't one.
You can use fgets() to read a whole line, then use explode() to split it into an array at the delimiters:
$line = fgets(STDIN);
$line = rtrim($line); // remove the newline
$arr = explode("\t", $line);
Or use fgetcsv() to do this in one step:
$arr = fgetcsv(STDIN, 0, "\t");
Related
This question already has answers here:
How can I explode a string by more than one space, but not by exactly one space in php
(2 answers)
Closed 8 months ago.
I am reading from files and each line has multiple spaces. Example:
$line = 'Testing Area 1 10x10';
I need to convert it into array with 3 elements only so I can save it to a table. Final output should be like this:
$final_array = array('Testing Area', '1', '10x10');
This is how I'm doing it so far:
// read by line
foreach(explode(PHP_EOL, $contents) as $line) {
// split line by 2 spaces coz distance between `1` and `10x10` is atleast 2 spaces
$arr = explode(' ', $line);
// But because `Testing Area` and `1` has so many spaces between them,
// exploding the $line results to empty elements.
// So I need to create another array for the final output.
$final_array = array();
// loop through $arr to check if value is empty
// if not empty, push to $final array
foreach ($arr as $value) {
if (!empty($value)) {
array_push($final_array, $value);
}
}
// insert into table the elements of $final_array according to its column
}
Is there a better way to do this instead of looping through the array and checking each element if it's empty?
Take note that I have multiple files to read, each containing atleast 200 lines like that.
Use preg_split(), with 2 or more spaces as the delimiter.
$array = preg_split('/\s{2,}/', $line);
Assuming the criteria for splitting be two or more spaces, we can try using preg_split here:
$line = 'Testing Area 1 10x10';
$final_array = preg_split("/\s{2,}/", $line);
print_r($final_array);
This prints:
Array
(
[0] => Testing Area
[1] => 1
[2] => 10x10
)
I have a simple string. I need to produce an output Array such that the order of every 2 consecutive characters is reversed.
Input string is 14f05000034e69 and I need the following output Array [4, 1, 0, f, 0, 5, 0, 0, 4, 3, 6, e, 9, 6].
Here is my PHP code:
$myString = "14f05000034e69";
$myStringArray = str_split($myString);
$newArray = array();
for ($index=0; $index<count($myStringArray)-1; $index+2) {
$newArray[] = $myStringArray[$index+1];
$newArray[] = $myStringArray[$index];
}
print_r($newArray);
And it is giving me
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 134217736 bytes) in /var/www/html/test.php on line 8
The question is why and how do I fix it?
<?php
$myString = "14f05000034e69";
$myStringArray = str_split($myString);
$i=0;
foreach($myStringArray as $row){
if(array_key_exists($i,$myStringArray)) {
$newArray[$i] = $myStringArray[$i + 1];
$newArray[$i + 1] = $myStringArray[$i];
$i = $i + 2;
}
}
echo '<pre>';
print_r($newArray);
I found a workaround in a bit "dirty" way but i managed to do what you asked.
Basically i split the string like you did but i play with the new array positions around and push in my new array the positions that i want to that's why i used a counter for that.
The output is:
Array
(
[0] => 4
[1] => 1
[2] => 0
[3] => f
[4] => 0
[5] => 5
[6] => 0
[7] => 0
[8] => 3
[9] => 0
[10] => e
[11] => 4
[12] => 9
[13] => 6
)
Basically i thought that i need to loop the array by two but every time i loop i need to handle 2 array positions and then the next two.
So that led me to handle my $new_array in a way that i push at the same time data in the current position i am and in the next position, that's why the counter $i+1 is used to handle array position.
If i did not use it there and used simple $newArray[] it would put the data in my current position and overwrite it again in the second step and also i could not move my array pointer to positions 1,3,5,6 etc etc that's why i am "forcing" it to use my $i counter so i keep pointing every after position.
My $i counter is set at the end of each loop to move with step 2.
The shortest alternative I could come up with is to use some of the array methods instead...
$myString = "14f05000034e69";
$out = str_split(implode(array_map ('strrev', str_split($myString, 2))));
print_r( $out );
This uses str_split() to split it into 2 char chunks, then uses array_map() and strrev() to reverse each item and then implode() to put them all back again.
The outer call to str_split() just splits the result back down to 1 char elements in an array for the output (miss this off if you just need the string itself)
In my opinion, the str_split is redundant in this operation, strings can be iterated through as of arrays, like this:
$myString = "14f05000034e69";
$newArray = array();
for ($index=0; $index<strlen($myString)-1; $index+=2)
{
$newArray[] = $myString[$index+1];
$newArray[] = $myString[$index];
}
print_r($newArray);
But yeah, as said before, just missing += in the for loop.
I made a small test on regex to see if it could be done, works as a charm. But of course, I only deliver a string in this case. :)
$myString = "14f05000034e69";
$test = preg_replace('/(.)(.)/', '$2$1', $myString);
echo $test;
This is the most elegant solution I could come up with.
Code tested here: https://3v4l.org/mtdca
And for the regex: https://3v4l.org/nI4UP
An answer has already been marked as the solution an many other answers too however I think this can help to know that we can achieve the inversion in the string itself and then split it.If an array is not needed we can just keep the string.This way we use less memory i think:
$myString = "14f05000034e69";
$length=strlen($myString);
for ($index=-1, $length=$length%2==0?$length-1:$length-2; $index<$length-1; $index+=2) {
$tmp=$myString[$index+1];
$myString[$index+1]=$myString[$index+2];
$myString[$index+2]=$tmp;
}
print_r(str_split($myString));// return an array
print_r($myString); //here a string
This can handle variable length of strings
I have one text file in directory. I want to get contents of that text file.
in my text file
student&class&mark&grade
I am trying to my code here.
$myfile = "data.txt" ;
$getdata = file($myfile) ;
print_r($getdata) ; // student&class&mark&grade // working fine.
I'm trying to explode function
$arr = explode('&',$getdata);
print_r($arr); // not working
how to solve this problem ?
file() function return the data in array - file function
file_get_contents() return the data in string form
Try file_get_contents() - file_get_contents
$myfile = "data.txt" ;
$getdata = file_get_contents($myfile) ;
$arr = explode('&',$getdata);
print_r($arr); // Will work
file() returns an array of the lines of the file, so this is the main problem. You will also find that file() will, by default, include a new line on the end of each line - which you probably don't want.
This code uses array_walk() to process each line, using explode() on a line at a time, replacing the original line with the array.
$getdata = file($myfile, FILE_IGNORE_NEW_LINES);
array_walk ( $getdata, function ( &$data ) { $data = explode("&", $data);});
print_r($getdata);
This outputs...
Array
(
[0] => Array
(
[0] => student
[1] => class
[2] => mark
[3] => grade
)
)
Example
I have CSV file that contains data of random number example data in CSV :
639123456789,73999999999,739222222222,839444444444,8639555555555....more
So, if I upload it, I want it to explode in a variable or in an array as long as I get the specific data. example of data I want to get is all 2 first line starting at 73 be extract so meaning all numbers that start with 73 only.
Example: 73999999999,739222222222
I have tried it by using only 1 number using split,substr and explode function but my problem is if the user input a CSV bulk data with no limit.
You can use substr() and loop through your array deleting the elements that do not match.
$str = '639123456789,73999999999,739222222222,839444444444,8639555555555';
$array = explode(',', $str); //Convert your string to an array.
$searchString = '73'; //Set the value your looking for.
foreach($array as $key=>$value){
if(substr($value, 0, 2) != $searchString){ //This will test first two characters.
unset($array[$key]);
}
}
$array = array_values($array);
print_r($array);
This will output:
Array
(
[0] => 73999999999
[1] => 739222222222
)
Updated
This will make a new array with only the numbers you want in it, leaving the original array untouched.
$str = '639123456789,73999999999,739222222222,839444444444,739222222222,839444444444,839444444444,73999999999';
$array = explode(',', $str);
$searchString = '73';
foreach($array as $key=>$value){
if(substr($value, 0, 2) == $searchString){
$results[] = $value;
}
}
print_r($results);
Well, my question is very simple, but I didn't find the proper answer in nowhere. What I need is to find a way that reads a .txt file, and if there's a duplicated line, remove ALL of them, not preserving one. For example, in a .txt contains the following:
1234
1233
1232
1234
The output should be:
1233
1232
Because the code has to delete the duplicated line, all of them. I searched all the web, but it always point to answers that removes duplicated lines but preserve one of them, like this, this or that.
I'm afraid that the only way to do this is to read the x line and check the whole .txt, if it finds an equal result, delete, and delete the x line too. If not, change to the next line. But the .txt file I'm checking has 50 milions lines (~900Mb), I don't know how much memory I need to do this kind of task, so I appreciate some help here.
Read the file line by line, and use the line contents as the key of an associative array whose values are a count of the number of times the line appears. After you're done, write out all the lines whose value is only 1. This will require as much memory as all the unique lines.
$lines = array();
$fd = fopen("inputfile.txdt", "r");
while ($line = fgets($fd)) {
$line = rtrim($line, "\r\n"); // ignore the newline
if (array_key_exists($line, $lines)) {
$lines[$line]++;
} else {
$lines[$line] = 1;
}
}
fclose($fd);
$fd = fopen("outputfile.txt", "w");
foreach ($lines as $line => $count) {
if ($count == 1) {
fputs($fd, "$line" . PHP_EOL); // add the newlines back
}
}
I doubt there is one and only one function that does all of what you want to do. So, this breaks it down into steps...
First, can we load a file directly into an array? See the documentation for the file command
$lines = file('mytextfile.txt');
Now, I have all of the lines in an array. I want to count how many of each entry I have. See the documentation for the array_count_values command.
$counts = array_count_values($lines);
Now, I can easily loop through the array and delete any entries where the count>1
foreach($counts as $value=>$cnt)
if($cnt>1)
unset($counts[$value]);
Now, I can turn the array keys (which are the values) into an array.
$nondupes = array_keys($counts);
Finally, I can write the contents out to a file.
file_put_contents('myoutputfile.txt', $nondupes);
I think I have a solution far more elegant:
$array = array('1', '1', '2', '2', '3', '4'); // array with some unique values, some not unique
$array_count_result = array_count_values($array); // count values occurences
$result = array_keys(array_filter($array_count_result, function ($value) { return ($value == 1); })); // filter and isolate only unique values
print_r($result);
gives:
Array
(
[0] => 3
[1] => 4
)