Php combine identical lines in text file

I have the following code

Code:

$fp = fopen('/output/report_sort.txt', 'w');
if(!$fp)
die('Could not create / open text file for writing.');
if(fwrite($fp, $txt1) === false)
die('Could not write to text file.');

// Print the totals for each category
$data = file('/output/report_sort.txt', FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
usort($data, fn($a, $b)=>substr($a,11,2)<=>substr($b,11,2));              // sort by code number
$codes = [];
foreach ($data as $d) {
$p = strpos($d, ')');
$k = substr($d, 11, $p-10);
if (!isset($codes[$k])) {
$codes[$k] = 1;
} else {
$codes[$k]++;
}
}
//echo (join("<br>", $data));
echo ("<font color='blue'><b><h3>Total clicks</h3></b></font>");
foreach ($codes as $code => $total)  {
printf("%s <font color='red'><b>Total clicks = %d<br></b></font>", $code, $total);
}
echo "<br />";

which from this data

Code:

05/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Spain Cartagena Murcia
05/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Spain Nerja Malaga
05/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 United States Cedar Springs Michigan
05/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Spain Madrid Madrid
06/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 United States Edmore Michigan
06/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 United States Edmore Michigan
06/10/2023 03 Resist the Curse (Resiste la Maldición) 11-12-2022.mp3 France 
08/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 United States Edmore Michigan
08/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 United States Edmore Michigan
08/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Ireland Dublin Leinster
08/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Ireland Dublin Leinster
09/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Ireland Dublin Leinster
09/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Ireland Dublin Leinster
09/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Ireland Dublin Leinster
09/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Ireland Dublin Leinster
09/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Ireland Dublin Leinster
09/10/2023 23 The Wedding Part 1 (La Boda) 30-7-2023.mp3 Ireland Dublin Leinster

22/09/2023 05 Day of Atonement 2023 (Día de la Expiación) 17-9-2023.mp3 Spain Nerja Malaga
22/09/2023 05 Day of Atonement 2023 (Día de la Expiación) 17-9-2023.mp3 Spain Cartagena Murcia

outputs the totals for each category as follows

Code:

03 Resist the Curse (Resiste la Maldición) Total clicks = 2
04 Feast of Trumpets 2023 (Fiesta de las Trompetas) Total clicks = 19
05 Day of Atonement 2023 (Día de la Expiación) Total clicks = 32
06 Feast of Tabernacles 2023 (Fiesta de los Tabernáculos) Total clicks = 4
07 The Eighth Day 2023 (El Octavo Día) Total clicks = 17
19 The Bread of Life (El Pan de la Vida) Total clicks = 20
20 Be With Me Where I Am (Está Conmigo Donde Estoy) Total clicks = 4
20 The Legacy of Jesus (El Legado de Jesús) Total clicks = 2
23 The Wedding Part 1 (La Boda) Total clicks = 1

what I would like is to combine lines which are duplicated to show 1 line as 1 click as follows

Code:

05/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Spain Cartagena Murcia
05/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Spain Nerja Malaga
05/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 United States Cedar Springs Michigan
05/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Spain Madrid Madrid
06/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 United States Edmore Michigan
06/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 United States Edmore Michigan
06/10/2023 03 Resist the Curse (Resiste la Maldición) 11-12-2022.mp3 France 
08/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 United States Edmore Michigan
08/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 United States Edmore Michigan
08/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Ireland Dublin Leinster
08/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Ireland Dublin Leinster
09/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Ireland Dublin Leinster
09/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Ireland Dublin Leinster
09/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Ireland Dublin Leinster
09/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Ireland Dublin Leinster
09/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Ireland Dublin Leinster

What I am wanting to do is a sort per country and city i.e for data

The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3

the totals would be
05/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Spain Cartagena Murcia Total clicks = 1
05/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Spain Nerja Malaga Total clicks = 1
05/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 United States Cedar Springs Michigan Total clicks = 1
05/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Spain Madrid Madrid Total clicks = 1
06/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 United States Edmore Michigan Total clicks = 4
08/10/2023 07 The Eighth Day 2023 (El Octavo Día) 1-10-2023.mp3 Ireland Dublin Leinster Total clicks = 7

Then the same for each category

While you should just use a database for this, that is probably not what the assignment is about?

I would parse the data into an array of columns at the earliest point, then operate on the parsed data. This will result in the fastest and clearest code. You should also pull out any repeated value, such as the file name, so that it can be set or changed at a single point.

Note: because the country, state, and city information is ambiguous, I just treated it as a location. The data should actually be stored as a valid CSV (Comma Separated Value) format or have some other delimiter between the separate fields.

Your first example would become -

$file = '/output/report_sort.txt';

$fp = fopen($file, 'w');
if(!$fp)
die('Could not create / open text file for writing.');
if(fwrite($fp, $txt1) === false)
die('Could not write to text file.');

$data = file($file, FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);

// call-back function to parse the lines of data
function _parse($line)
{
	$arr['date'] = substr($line,0,10);
	$arr['code'] = substr($line,11,2);
	$p = strpos($line, ')');
	$arr['title'] = substr($line, 14, $p-13);
	$parts = explode(' ',substr($line, $p+2));
	$arr['file'] = $parts[0];
	$arr['location'] = implode(' ',array_slice($parts,1));
	return $arr;
}

// parse the data at the earliest point, then operate on the parsed data
$data = array_map('_parse',$data);

// sort by the 'code' column
usort($data, fn($a, $b)=>$a['code']<=>$b['code']);

// Print the totals for each category
$codes = [];
foreach ($data as $arr)
{
	$k = "{$arr['code']} {$arr['title']}";
	if(!isset($codes[$k]))
	{
		$codes[$k] = 0;
	}
	$codes[$k]++;
}
echo "<font color='blue'><b><h3>Total clicks</h3></b></font>";
foreach ($codes as $code => $total)
{
	printf("%s <font color='red'><b>Total clicks = %d<br></b></font>", $code, $total);
}
echo "<br />";

For the question asked, the code would look like -

$file = '/output/report_sort.txt';

$fp = fopen($file, 'w');
if(!$fp)
die('Could not create / open text file for writing.');
if(fwrite($fp, $txt1) === false)
die('Could not write to text file.');

$data = file($file, FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);

// call-back function to parse the lines of data
function _parse($line)
{
	$arr['date'] = substr($line,0,10);
	$arr['code'] = substr($line,11,2);
	$p = strpos($line, ')');
	$arr['title'] = substr($line, 14, $p-13);
	$parts = explode(' ',substr($line, $p+2));
	$arr['file'] = $parts[0];
	$arr['location'] = implode(' ',array_slice($parts,1));
	return $arr;
}

// parse the data at the earliest point, then operate on the parsed data
$data = array_map('_parse',$data);

// search for - 'The Eighth Day 2023 (El Octavo Día)'
// define a search term
$search = ['key'=>'title', 'value'=>'The Eighth Day 2023 (El Octavo Día)'];

// use array_filter() with a call-back function to keep only the data matching the search term
$data = array_filter(
		$data,
		function ($arr) use ($search) {
			return isset($arr[$search['key']]) && $arr[$search['key']] == $search['value'];
		}
	);

// get the one-time heading data
$row = current($data);
// note: because there are multiple dates per location, it doesn't make much sense to display the date as part of each result
$heading = "{$row['code']} {$row['title']} {$row['file']} ";

// produce the count per location
$codes = [];
foreach ($data as $arr)
{
	$k = $arr['location'];
	if(!isset($codes[$k]))
	{
		$codes[$k] = 0;
	}
	$codes[$k]++;
}
echo "<font color='blue'><b><h3>Total clicks</h3></b></font>";
foreach ($codes as $code => $total)
{
	printf("%s <font color='red'><b>Total clicks = %d<br></b></font>", $heading.$code, $total);
}
echo "<br />";
Sponsor our Newsletter | Privacy Policy | Terms of Service