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";
?>
Related
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?
I have this situation in PHP. I have an array that has these keys for example, wires-1, wires-2, wires-3. I need a function or way for my program to read these keys, and find that the common word is wires? How would that be accomplished in PHP? Thanks for your help.
Take a look at how an autocomplete's functionality works, this is similar to your approach.
I'm sure there's plenty of source codes for autocomplete on google
For the string value of every key in your array:
Throw away all non-alpha characters, i.e. leave only letters such that ctype_alpha($remaining_text) should return true.
Keep an array with the found words as keys, and their frequencies as values, as such:
$array = new array();
function found_word($word)
{ global $array;
if(!isset($array[$word])) { $array[$word] = 1; }
else { $array[$word]++; }
}
Only nicer ;)
Sort the array in reverse by using arsort($array);
$array now contains the most found words as its first elements.
you would have to create every possible suffix of every string you have.
create a map for every suffix you found
count the occurence of every suffix in your string array
you can modify the performance with f.ex. limiting the suffix length
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!
I need to count the number of equal signs in a line. What is the best way of doing this. The text file is also pretty large, so if possible I would first like to check to see if an equal sign is in the line at all and then count them (if this would be faster). I do not need to know how to loop through the lines (I already know this part). Also if there is a way to do it so if it hits a certain number (for instance if more than 5 equal signs are in the line) that would would automatically stop (if this speeds things up).
Regards,
Use substr_count. It returns the number of substring occurences in a line.
For example:
$count = substr_count( $line, '=' );
As for counting occurrences, just use substr_count().
Assuming you know how to buffer input the file (rather than trying to load it all into memory at once), you pretty much have to start at the beginning to do a correct line count either to filter to a particular range of line numbers or simply to identify the line number. Lines are variable length after all.
This uses preg_match_all() for each line. Is that what you are looking for?
$fil = file("listcontent.php");
foreach ( $fil as $line ) {
$matches = array();
$count = preg_match_all("/(=[^=]*)/",$line,$matches);
if ( $count ) echo $count.": ".$line;
}
I had no idea to correctly form the title of this question, because I don't even know if what I'm trying to do has a name.
Let's say I've got an external file (called, for instance, settings.txt) with the following in it:
template:'xaddict';
editor:'true';
wysiwyg:'false';
These are simple name:value pairs.
I would like to have php take care of this file in such a way that I end up with php variables with the following values:
$template = 'xaddict';
$editor = 'true';
$wysiwyg = 'false';
I don't know how many of these variables I'll have.
How should i go and do this?
The data inside the file is in simple name:value pairs. No nesting, no complex data. All the names need to be converted to $name and all the values need to be converted to 'value', disregarding whether it is truly a string or not.
$settings = json_decode(file_get_contents($filename));
assuming your file is in valid JSON format. If not, you can either massage it so it is or you'll have to use a different approach.
Do you want 'true' in "editor:'true'" to be interpreted as a string or as a boolean? If sometimes string, sometimes boolean, how do you know which?
If you have "number='9'" do you want '9' interpreted as a string or an as an integer? Would '09' be a decimal number or octal? How about "number='3.14'": string or float? If sometimes one, sometimes the other, how do you know which?
If you have "'" (single quote) inside a value is it escaped? If so, how?
Is there any expectation of array data?
Etc.
Edit: This would be the simplest way, imo, to use your example input to retrieve your example data:
$file = 'test.csv';
$fp = fopen($file, 'r');
while ($line = fgetcsv($fp, 1024, ':')) {
$$line[0] = $line[1];
}
If you use JSON, you can use something like:
extract(json_decode(file_get_contents('settings.json')));
Using extract may be dangerous, so I suggest to store these settings in an array:
$settings = json_decode(file_get_contents('settings.json'));
You should read your file to an array, with the file() function, then you should cycle on it: for each line (the file() function will return an array, one line per item), check if the line is not blank, then explode() on the ":" character, trim the pieces, and put them into an array.
You will end up win an array like this:
[template] = xaddict
[editor] = true
then you can use this information.
Do not automatically convert this into local variables: it's a great way to introduce security risks, and potentially very obscure bugs (local variables obscured by those introduced by this parsing).