Elegant way to force two array elements when splitting a string - php

Assume the following string:
$string = 'entry1_entry2';
What I want to do is something like this:
list($entry1, $entry2) = explode('_', $string);
My question now is are there any elegant ways to force the explode (or any other function) to get 2 array items minimum? You could specify a third parameter to get a maximum of 2 elements but I want a minimum. If there would be a string like this:
$string = 'entry1';
The second line would give a NOTICE because there is only one array element. The best would be a way without checking the resulting array or the string for the presence of the seperator.

You could probably use array_pad:
list($entry1, $entry2) = array_pad(explode('_', $string), 2, NULL);
See array_pad

I'd suggest that storing the explode inside multiple variables is just bad practice, when you can't enforce the integrity of your data.
Should you not simply be using
$entries = explode($string);
and avoid all the unnecessary complications?

Related

Can I collect explode then explode again?

I'm trying to create data save variable using a text file. I read that the collect function in laravel is the right choice for managing the data.
Here is the data saved after I exploded with PHP_EOL :
What I want to do is explode once more per array with "|", so my code is like this but it can't.
$temps=explode(PHP_EOL,$note);
$isi=collect([
explode('|',$temps)
]);
This code can only be applied if it is accompanied by a manual array like this :
$isi=collect([
explode('|',$temps[0]),
explode('|',$temps[2])
]);
The dd output:
As I think you've worked out, explode returns an array but accepts a string, so you can't pass the result of explode directly to another explode call.
Instead you need to get each individual string in the array produced by the first explode, and explode each one separately.
Clearly it's not practical to try and hard-code a reference to each item of the array (as per your attempt), so instead you can use a loop to fetch each item, or a slightly neater way is to use array_map, like in the following example:
function pipeExplode($str)
{
return explode("|", $str);
}
$text = "sdlkfjsdl|kwflwerflwekr|wlkjlgk4w\n3rtljhrfgkjed|3jhkrjghd|4t44thj\n33rtlhwege|3rth3herjgke|hkjfgdf";
$arr = explode(PHP_EOL, $text);
$finalArr = array_map('pipeExplode', $arr);
print_r($finalArr);
Demo: https://3v4l.org/EM6Ct
This will take each string from the first array, pass it through the pipeExplode function to get a new array back from that, and then add that array back into the outer array which is returned by the array_map function.

How To Get The Unique Name Count With PHP?

Let's say I have text file Data.txt with:
26||jim||1990
31||Tanya||1942
19||Bruce||1612
8||Jim||1994
12||Brian||1988
56||Susan||2201
and it keeps going.
It has many different names in column 2.
Please tell me, how do I get the count of unique names, and how many times each name appears in the file using PHP?
I have tried:
$counts = array_count_values($item[1]);
echo $counts;
after exploding ||, but it does not work.
The result should be like:
jim-2,
tanya-1,
and so on.
Thanks for any help...
Read in each line, explode using the delimiter (in this case ||), and add it to an array if it does not already exist. If it does, increment the count.
I won't write the code for you, but here a few pointers:
fread reads in a line
explode will split the line based on a delimiter
use in_array to check if the name has been found before, and to determine whether you need to add the name to the array or just increment the count.
Edit:
Following Jon's advice, you can make it even easier for you.
Read in line-by-line, explode by delimiter and dump all the names into an array (don't worry about checking if it already exists). After you're done, use array_count_values to get every unique name and its frequency.
Here's my take on this:
Use file to read the data file, producing an array where each element corresponds to a line in the input.
Use array_filter with trim as the filter function to remove blank lines from this array. This takes advantage that trim returns a string having removed whitespace from both ends of its argument, leaving the empty string if the argument was all whitespace to begin with. The empty string converts to boolean false -- thus making array_filter disregard lines that are all whitespace.
Use array_map with a callback that involves calling explode to split each array element (line of text) into three parts and returning the second of these. This will produce an array where each element is just a name.
Use array_map again with strtoupper as the callback to convert all names to uppercase so that "jim" and "JIM" will count as the same in the next step.
Finally, use array_count_values to get the count of occurrences for each name.
Code, taking things slowly:
function extract_name($line) {
// The -1 parameter (available as of PHP 5.1.0) makes explode return all elements
// but the last one. We want to do this so that the element we are interested in
// (the second) is actually the last in the returned array, enabling us to pull it
// out with end(). This might seem strange here, but see below.
$parts = explode('||', $line, -1);
return end($parts);
}
$lines = file('data.txt'); // #1
$lines = array_filter($lines, 'trim'); // #2
$names = array_map('extract_name', $lines); // #3
$names = array_map('strtoupper', $names); // #4
$counts = array_count_values($names); // #5
print_r($counts); // to see the results
There is a reason I chose to do this in steps where each steps involves a function call on the result of the previous step -- that it's actually possible to do it in just one line:
$counts = array_count_values(
array_map(function($line){return strtoupper(end(explode('||', $line, -1)));},
array_filter(file('data.txt'), 'trim')));
print_r($counts);
See it in action.
I should mention that this might not be the "best" way to solve the problem in the sense that if your input file is huge (in the ballpark of a few million lines) this approach will consume a lot of memory because it's reading all the input in memory at once. However, it's certainly convenient and unless you know that the input is going to be that large there's no point in making life harder.
Note: Senior-level PHP developers might have noticed that I 'm violating strict standards here by feeding the result of explode to a function that accepts its argument by reference. That's valid criticism, but in my defense I am trying to keep the code as short as possible. In production it would be indeed better to use $a = explode(...); return $a[1]; although there will be no difference as regards the result.
While I do feel that this website's purpose is to answer questions and not do homework assignments, I don't acknowledge the assumption that you are doing your homework, since that fact has not been provided. I personally learned how to program by example. We all learn our own ways, so here is what I would do if I were to attempt to answer your question as accurately as possible, based on the information you have provided.
<?php
$unique_name_count = 0;
$names = array();
$filename = 'Data.txt';
$pointer = fopen($filename,'r');
$contents = fread($pointer,filesize($filename));
fclose($pointer);
$lines = explode("\n",$contents);
foreach($lines as $line)
{
$split_str = explode('|',$line);
if(isset($split_str[2]))
{
$name = strtolower($split_str[2]);
if(!in_array($name,$names))
{
$names[] = $name;
$unique_name_count++;
}
}
}
echo $unique_name_count.' unique name'.(count($unique_name_count) == 1 ? '' : 's').' found in '.$filename."\n";
?>

PHP : How to get the current value of an array being traversed within an inbuilt function like strpos?

eg. I want to replace instances of some words with their string length
"XXXX is greater than XX" becomes "4 is greater than 2"
Code that I intend to write :
$myStrings = Array("XX","XXX","XXXX","XXXXX");
$outStr = str_replace($myStrings,strlen(current($myStrings)),$outStr);
But here CURRENT is not working.
P.S. Please do not suggest workarounds to do this stuff since that is not what I intend to ask the forum. My query is getting current pointer to an array being traversed internally.
Thank You.
The function you are looking for is array_map. It applies a function to all elements of an array and outputs the results as a new array:
$myStrings = Array("XX","XXX","XXXX","XXXXX");
$outStr = str_replace($myStrings,array_map('strlen', $myStrings)),$outStr);
This might create a new problem as XXXX will be replaced with 22 before XXXX is checked. The solution to this would be reverse the input array:
$myStrings = array_reverse(Array("XX","XXX","XXXX","XXXXX"));
$outStr = str_replace($myStrings,array_map('strlen', $myStrings)),$outStr);
I don't think you can. Since it's an internal implementation, what would PHP expose to you that you could use to determine the current element?
Note that this is different from accessing internal array pointers using current(), key(), next(), reset() et al. I'm referring to the fact that PHP has an internal implementation of str_replace() for handling replacements of arrays of strings.
A quick test reveals that PHP doesn't even seem to bother with array pointers when replacing them with str_replace() anyway:
$arr = array('a', 'b', 'c'); // Internal pointer is at a
$str = 'abc';
next($arr); // Internal pointer is at b
echo str_replace($arr, 'x', $str), "\n"; // xxx
echo current($arr), "\n"; // b
Oh, by the way, this is what the manual for str_replace() says (strong emphasis mine):
If search is an array and replace is a string, then this replacement string is used for every value of search.
So specifically for str_replace(), I don't think it was ever intended for you to pass in a replacement string that is dynamic based on the input array.
And http://www.php.net/manual/de/function.array-walk.php isnĀ“t an option?

How to access array index when using explode() in the same line?

Can't wrap my head around this...
Say, we explode the whole thing like so:
$extract = explode('tra-la-la', $big_sourse);
Then we want to get a value at index 1:
$finish = $extract[1];
My question is how to get it in one go, to speak so. Something similar to this:
$finish = explode('tra-la-la', $big_sourse)[1]; // does not work
Something like the following would work like a charm:
$finish = end(explode('tra-la-la', $big_sourse));
// or
$finish = array_shift(explode('tra-la-la', $big_sourse));
But what if the value is sitting somewhere in the middle?
Function Array Dereferencing has been implemented in PHP 5.4. For older version that's a limitation in the PHP parser that was fixed in here, so no way around it for now I'm afraid.
Something like that :
end(array_slice(explode('tra-la-la', $big_sourse), 1, 1));
Though I don't think it's better/clearer/prettier than writing it on two lines.
you can use list:
list($first_element) = explode(',', $source);
[1] would actually be the second element in the array, not sure if you really meant that. if so, just add another variable to the list construct (and omit the first if preferred)
list($first_element, $second_elment) = explode(',', $source);
// or
list(, $second_element) = explode(',', $source);
My suggest - yes, I've figured out something -, would be to use an extra agrument allowed for the function. If it is set and positive, the returned array will contain a maximum of limit elements with the last element containing the rest of string. So, if we want to get, say, a value at index 2 (of course, we're sure that the value we like would be there beforehand), we just do it as follows:
$finish = end(explode('tra-la-la', $big_sourse, 3));
explode will return an array that contains a maximum of three elements, so we 'end' to the last element which the one we looked for, indexed 2 - and we're done!

remove duplicate from string in PHP

I am looking for the fastest way to remove duplicate values in a string separated by commas.
So my string looks like this;
$str = 'one,two,one,five,seven,bag,tea';
I can do it be exploding the string to values and then compare, but I think it will be slow. what about preg_replace() will it be faster? Any one did it using this function?
The shortest code would be:
$str = implode(',',array_unique(explode(',', $str)));
If it is the fastest... I don't know, it is probably faster then looping explicitly.
Reference: implode, array_unique, explode
Dealing with: $string = 'one,two,one,five,seven,bag,tea';
If you are generating the string at any point "up script", then you should be eliminating duplicates as they occur.
Let's say you are using concatenation to generate your string like:
$string='';
foreach($data as $value){
$string.=(strlen($string)?',':'').some_func($value);
}
...then you would need to extract unique values from $string based on the delimiter (comma), then re-implode with the delimiter.
I suggest that you design a more direct method and deny duplicates inside of the initial foreach loop, like this:
foreach($data as $value){
$return_value=some_func($value); // cache the returned value so you don't call the function twice
$array[$return_value]=$return_value; // store the return value in a temporary array using the function's return value as both the key and value in the array.
}
$string=implode(',',$array); // clean: no duplicates, no trailing commas
This works because duplicate values are never permitted to exist. All subsequent occurrences will be used to overwrite the earlier occurrence. This function-less filter works because arrays may not have two identical keys in the same array(level).
Alternatively, you can avoid "overwriting" array data in the loop, by calling if(!isset($array[$return_value])){$array[$return_value]=$return_value;} but the difference means calling the isset() function on every iteration. The advantage of using these associative key assignments is that the process avoids using in_array() which is slower than isset().
All that said, if you are extracting a column of data from a 2-dimensional array like:
$string='';
foreach($data as $value){
$string.=(strlen($string)?',':'').$value['word'];
}
Then you could leverage the magic of array_column() without a loop like this:
echo implode(',',array_column($str,'word','word'));
And finally, for those interested in micro-optimization, I'll note that the single call of array_unique() is actually slower than a few two-function methods. Read here for more details.
The bottomline is, there are many ways to perform this task. explode->unique->implode may be the most concise method in some cases if you aren't generating the delimited string, but it is not likely to be the most direct or fastest method. Choose for yourself what is best for your task.

Categories