Finding duplicate values in multidimensional array - php

I'm trying to code a system which will find user accounts that are using the same IPs, and print out the matches with their keys. I have already coded the part where the data is pulled from MySQL and nicely put in a multidimensional associative array, so input looks like this (the key is UserID, values are IP addresses):
$users = array(
100 => array("1.1.1.1","2.2.2.2","3.3.3.3"),
200 => array("1.1.1.1","4.4.4.4","5.5.5.5"),
300 => array("1.1.1.1","4.4.4.4","7.7.7.7")
);
The expected output would be:
Array
(
[1.1.1.1] => Array
(
[0] => 100
[1] => 200
[2] => 300
)
[4.4.4.4] => Array
(
[0] => 200
[1] => 300
)
)
I have searched and used trial and error with multiple nested foreach that would loop through the arrays, tried array_intersect to find the duplicates, but nothing gets me close to the expected output. By now I think I'm overthinking the problem and the solution is really easy, but I cannot seem to get close to the expected output. Any help is appreciated, thank you.

$output = array();
// loop through each user
foreach ($users as $id => $ips) {
// loop through each IP address
foreach ($ips as $ip) {
// add IP address, if not present
if (!isset($output[$ip])) {
$output[$ip] = array();
}
// add user ID to the IP address' array
$output[$ip][] = $id;
}
}

$users = array(
100 => array("1.1.1.1","2.2.2.2","3.3.3.3"),
200 => array("1.1.1.1","4.4.4.4","5.5.5.5"),
300 => array("1.1.1.1","4.4.4.4","7.7.7.7")
);
$allIP = [];
foreach ( $users as $user ) {
$allIP = array_merge($allIP, $user);
}
$allIP = array_unique($allIP);
$result = [];
foreach ( $allIP as $ip ) {
foreach ( $users as $key => $val ) {
if ( in_array($ip, $val, true) ) {
if ( !isset($result[$ip]) ) {
$result[$ip] = [];
}
array_push($result[$ip], $key);
}
}
}
$result = array_filter($result, function ($v, $k) {
if ( count($v) > 1 ) {
return true;
} else {
return false;
}
}, ARRAY_FILTER_USE_BOTH);
var_dump($result);
Although I think it's better to do this by SQL as well. It could be extremely slow to achieve this by PHP.

Related

Array unique values PHP

I want to find the Unique values by username:
so the resulting array would be [0] =>JakeP, [1]=>TomC
My code currently works, but I was wondering is there a better way to accomplish this task with less loops, or using array_unique function?
Array
(
[0] => Array
(
[ID] => 3
[Username] => TomC
[Project_Name] => Inventory
)
[1] => Array
(
[ID] => 4
[Username] => JakeP
[Project_Name] => Inventory
)
[2] => Array
(
[ID] => 2
[Username] => TomC
[Project_Name] => Stocks
)
[3] => Array
(
[ID] => 1
[Username] => Tomc
[Project_Name] => Stocks
)
)
My code which works is :
$names_filter = array();
foreach($latest_projects as $project)
{
if(empty($names_filter))
{
$names_filter[] = $project['Username'];
}
else {
foreach($names_filter as $key=>$value)
{
if($value == $project['Username'])
{ break; }
else
{
$names_filter[] = $project['Username'];
}
}
}
}
If you're using PHP >= 5.5 you can take advantage of the array_column() function:
$uniqueNames = array_unique(
array_column($myArray, 'Username')
);
Prior to PHP 5.5, you can use:
$uniqueNames = array_unique(
array_map(
function($value) {
return $value['Username'];
},
$myArray
)
);
You can use the in_array function to simplify your code. Example:
$names_filter = array();
foreach($latest_projects as $project)
{
if(!in_array($project['Username'], $names_filter))
{
$names_filter[] = $project['Username'];
}
}
The in_array() function checks for the existence of a value in an array. So the foreach loop will only add a project username to the $names_filter array if it's not in the array. The output should be a list of unique usernames in the $names_filter array.
We can loop through $latest_projects and store each user name to new array ($filter). Since array can't have two elements with same keys, if the key exists it will be overwritten.
$filter = array();
foreach ($latest_projects as $project)
{
$filter[$project['Username']] = 1;
}
$filter = array_keys($filter);
I can't speak to the performance of this over other solutions, but a similar effect can be achieved with the use of array_map and array_unique. It's not as readable either though, which is just as important.
$uniqueUsers = array_unique(array_map(function ($p) { return $p['Username']; }, $latest_projects));

PHP: How can I get the value from a key in a multiple array

The multiple array looks like
Array
(
[id] => description
[header] =>
[width] => 20
[dbfield] => description
[type] => text
)
Array
(
[id] => quantity
[header] => Menge
[dbfield] => QUANTITY_NEW
[width] => 60
[type] => decimal
)
How can I get the value from dbfield where id is 'quantity' without knowing the numeric value of the id?
The actual code looks like
foreach($array as $id => $fieldData) {
if($fieldData['type'] == 'decimal')
{
doSomething...();
}
}
In the part with doSomething I need access to other fields from the array, but I only know the id. I already tried it with dbfield['quantity']['dbfield'] etc. which obviously fails.
A simple alternative using array_keys:
function getValues($data, $lookForValue, $column)
{
$res = array();
foreach ($data as $key => $data)
{
if($idx = array_keys($data, $lookForValue))
{
$res[$idx[0]] = $data[$column];
}
}
return $res;
}
$values = getValues($myData, "quantity", "dbfield");
var_dump($values);
echo out the array as such..
$array = array();
$array['qty'] = 'qtty';
$array['dbfield'] = 'QUANTITY_NEW';
if($array['qty'] = 'qtty'){
echo $array['dbfield'];
}
returns - QUANTITY_NEW
You can do this with several methods, one of them is using array_map to get those values:
$dbfield = array_filter(array_map(function($a){
if($a["id"] === "quantity"){
return $a["dbfield"];
}
}, $array));
print_r($dbfield);
You iterate over the array, and return the key dbfield where id is 'quantity'. Array filter is just to not return null values where it doesn't have 'quantity' id.
Online attempt to reproduce your code can be found here

How to make an associative array with elements from an array as its key and use arrays for corresponding values?

I have arrays $devices,$port
print_r($devices);
Array(
[0] => cisco1
[1] => cisco2
)
print_r($port);
Array
(
[0] => Port1/1/1
[1] => Port1/1/10
[2] => Port1/1/11
)
I want to create an array $devlist which would be something like this:
Array(
[cisco1] =>Port1/1/1
Port1/1/10
Port1/1/11
[cisco2] =>Port2/1/1
Port2/1/10
Port2/1/11
)
My point is there is an array of devices($devices) and arrays of ports that are there in each of the device.
The $port array gets created newly for each device in the $device array.
What i have tried so far:
foreach ($devices as $value)
{
$port=();
//iam polling the respective device and getting a list of ports available for that device in array **$port**
array_push($devices[$value], $port);
}
This method generates an error "array_push() expects parameter 1 to be array, null given"
Kindly excuse me if this seems an easy question becoz iam new to php and scripting as well:(
Do you want something like this? If so, i don't understand why, when you could just use the values from $ports for each $device?
$devices = array
(
'cisco1', 'cisco2'
);
$ports = array
(
'Port1/1/1',
'Port1/1/10',
'Port1/1/11'
);
$dev_list = array();
foreach ($devices as $device)
{
$dev_list[$device] = array();
foreach ($ports as $port)
{
array_push($dev_list[$device], $port);
}
}
echo '<pre>';
print_r($dev_list);
echo '</pre>';
Array
(
[cisco1] => Array
(
[0] => Port1/1/1
[1] => Port1/1/10
[2] => Port1/1/11
)
[cisco2] => Array
(
[0] => Port1/1/1
[1] => Port1/1/10
[2] => Port1/1/11
)
)
Try this:
$devlist = array();
foreach ($devices as $value)
{
$port=();
//iam polling the respective device and getting a list of ports available for that device in array **$port**
$devlist[$value] = $port;
}
You may use a foreach or a for loop but the main thing is that you have to use variable variables.
Solution One:
$devlist = array();
foreach($devices as $key => $device){
$devlist[$device] = ${"port".($key+1)};
}
Solution Two:
$devlist = array();
$size = sizeof($devices);
for($i = 0; $i < $size; $i++){
$devlist[$devices[$i]] = ${"port".($i+1)};
}
If I understand your question, you want something like this:
$arr = array
(
'cisco1' => array
(
'Port1/1/1',
'Port1/1/10',
'Port1/1/11'
),
'cisco2' => array
(
'Port1/1/1',
'Port1/1/10',
'Port1/1/11'
)
);
foreach($arr as $key => $value) // use the foreach-loop like this to get both keys and values
{
echo "$key: <br />-" . implode('<br />-', $value) . '<br /><br />';
}
prints:
cisco1:
-Port1/1/1
-Port1/1/10
-Port1/1/11
cisco2:
-Port1/1/1
-Port1/1/10
-Port1/1/11

Retrieve subarray of array by key value

I have the following array (example, real one is larger)
Array
(
[0] => Array
(
[984ab6aebd2777ff914e3e0170699c11] => Array
(
[id] => 984ab6aebd2777ff914e3e0170699c11
[message] => Test1
)
[1] => Array
(
[ca403872d513404291e914f0cad140de] => Array
(
[id] => ca403872d513404291e914f0cad140de
[message] => Test2
)
)
[2] => Array
(
[ca403872d513404291e914f0cad140de] => Array
(
[id] => ca403872d513404291e914f0cad140de
[message] => Test3
)
[3] => Array
(
[ca403872d513404291e914f0cad140de] => Array
(
[id] => ca403872d513404291e914f0cad140de
[message] => Test4
)
)
)
Now I want to somehow "access" the subarray with a given id, e.g. access the subarray with ID 984ab6aebd2777ff914e3e0170699c11 and then proceed to use this array in a foreach like this..
foreach ($array_with_specific_id as $event) {
echo $event['message'];
}
Is this possible?
Edit:
DB code to produce array in my model:
public function get_event_timeline($id)
{
$data = array();
foreach ($id as $result) {
$query = $this->db->query("SELECT * FROM event_timeline WHERE id = ?", array($result['id']));
foreach ($query->result_array() as $row)
{
array_push($data, array($row['id'] => $row));
}
}
return $data;
}
When populating your array from the database you can cerate an additional $index array like the following scheme:
$index = array (
'984ab6aebd2777ff914e3e0170699c11' => ReferenceToElementInData,
'ca403872d513404291e914f0cad140de' => ReferenceToElementInData,
// ...
)
This can give you quick access to the elements via their id without an additional foreach loop. Of course it will need additional memory, but this should be ok as you will only save refrences to the original data. However, test it.
Here comes an example:
public function get_event_timeline($id)
{
$data = array();
// create an additional index array
$index = array();
// counter
$c=0;
foreach ($id as $result) {
$query = $this->db->query("SELECT * FROM event_timeline WHERE id = ?", array($result['id']));
// every entry in the index is an array with references to entries in $data
$index[$result['id']] = array();
foreach ($query->result_array() as $row)
{
array_push($data, array($row['id'] => $row));
// create an entry in the current index
$index[$row['id']][] = &$data[$c];
$c++;
}
}
return array (
'data' => $data,
'index' => $index
);
}
Now you can access the elements via the index array without an additional foreach loop:
$entry = $index['984ab6aebd2777ff914e3e0170699c11'][0];
If there are multiple results per $id (as you mentioned in the comments you can access them using index greater then zero:
$entry = $index['984ab6aebd2777ff914e3e0170699c11'][1];
$entry = $index['984ab6aebd2777ff914e3e0170699c11'][2];
You can get the count of items per $id by calling
$number = count($index['984ab6aebd2777ff914e3e0170699c11']);
That's much the same like indexes that where used in databases to speed up queries.
I'd probably just get rid of the containing array as it seems unnecessary. However, you could do something like:
function get_message($specific_id, $arrays) {
foreach($arrays as $array) {
if(in_array($specific_id, $array)) {
return $array['message'];
}
}
}
I haven't had a chance to test this, but it should work.
function doTheJob($inputArray, $lookingFor) {
foreach ($inputArray as $subArray) {
foreach ($subArray as $subKey => $innerArray) {
if ($subKey == $lookingFor) {
return $innerArray;
}
}
}
return NULL;
}
Alternatively, you can use array_filter instead of outer foreach.

PHP - how to compare value of arrays in dynamic way?

Ok, I have following 'challange';
I have array like this:
Array
(
[0] => Array
(
[id] => 9
[status] => 0
)
[1] => Array
(
[id] => 10
[status] => 1
)
[2] => Array
(
[id] => 11
[status] => 0
)
)
What I need to do is to check if they all have same [status].
The problem is, that I can have 2 or more (dynamic) arrays inside.
How can I loop / search through them?
array_diff does support multiple arrays to compare, but how to do it? :(
Which ever loop I have tried, or my Apache / browser died - or I got completely bogus data back.
You could just put the problem apart to make it easier to solve.
First get all status items from your array:
$status = array();
forach($array as $value)
{
$status[] = $value['status'];
}
You now have an array called $status you can see if it consists of the same value always, or if it has multiple values:
$count = array_count_values($status);
echo count($count); # number of different item values.
Try this code:
$status1 = $yourArray[0]['status'];
$count = count($yourArray);
$ok = true;
for ($i=1; $i<$count; $i++)
{
if ($yourArray[$i]['status'] !== $status1)
{
$ok = false;
break;
}
}
var_dump($ok);
function allTheSameStatus( $data )
{
$prefStatus = null;
foreach( $data as $array )
{
if( $prefStatus === null )
{
$prefStatus = $array[ 'status' ];
continue;
}
if( $prefStatus != $array[ 'status' ] )
{
return false;
}
}
return true;
}
I'm not sure what you want as output but you could iterate through the outer array and create an output array that groups the inner arrays by status:
$outputArray = array();
foreach ($outerArray as $an_array) {
$outputArray[$an_array['status']][] = $an_array['id'];
}

Categories