PHP 3D array count unique values - php

I have a 3D array. I need to extract the following:
the number of occurrences of unique items in deepest level array
the number of co-occurrences of certain items in deepest level array
Array looks like this:
$arr = (
[0] => array([0] => array([flag][token][value])
[1] => array([flag][token][value])
)
)
I tried looping through the array using a for loop and an if statement, like this:
$new_arr1 = ""; // $new_arr1 = array(); //same thing, the later code doesn't work
for ($i=0; $i<count($arr);$i++)
{
for ($j=0; $j<count($arr[$i]); $j++)
{
$value= $arr[$i][$j][value];
if ($arr[$i][$j][flag] == "noun")
array_push($new_arr1, $value)
elseif ($arr[$i][$j][flag] == "verb")
array_push($new_arr2, $value)
}
}
did the same thing with switch statement, couldn't get it to work. By doing this kind of conditioning I was hoping to get all of the values from the deepest level array that meet the certain criteria into one array, and then perform *array_count_values* on them. That would give me the following:
for flag == "noun", value of value element stored in $new_arr1, and for flag == "verb", value of value element stored in $new_arr2:
$new_arr1 = (
[dog] => 7
[cat] => 2
[horse] => 4
);
$new_arr2 = (
[chase] => 2
[eat] => 5
[pwn] => 3
);
this would give me a count of unique values of the deepes level array that I can't access using *array_uniqe* function.
Besides that, I need to perform a count of co-occurrences of these values, something like this:
count the number of times that some token with certain flag comes before or after another token with a certain flag:
pseudocode:
$count=0;
if ( (($arr[$i][$j][flag] == "noun") && ($arr[$i][$j][value] == "dog")) &&
(($arr[$i][$j+/-1][flag] == "verb") && ($arr[$i][$j+/-1][value] == "chase"))
)
$count++;
$counter = array($count = array($arr[$i][$j][value]), $arr[$i][$j+/-1][value])
that would basically give the following:
counter:
array(
"7" => ([0] => "dog", [1] => "chase")
"4" => ([0] => "cat", [1] => "eat")
)
where the "7" and "4" are the names of the associative array, while "dog" and "chase" are the values stored in another array.
)

I'm not sure if I follow your question 100%, but something like this might work:
$verb_array = array();
$noun_array = array();
foreach($arr as $index => $data){
if($data['flag'] == 'noun'){
if(isset($noun_array[$data['value']])){
$noun_array[$data['value']]++;
}
else{
$noun_array[$data['value']] = 0;
}
}
else if($data['flag'] == 'verb'){
if(isset($noun_array[$data['value']])){
$verb_array[$data['value']]++;
}
else{
$verb_array[$data['value']] = 0;
}
}
}
Then to get the count of occurrences:
$noun_count = count($noun_array);
$verb_count = count($verb_array);
And if you need the count of a particular item, it will exist inside of the array.

Related

How to check if value is equal to string in array

I want to check if the value: diam-mm exist in array, if the value not exist do something.
A array can have multiple properties, property name is: [PropertyType]->[Name]
i thought i loop to the properties and check if diam-mm value exist, else do something but because of the loop he does import the value mutliple times instead of one time.
Example of one array with properties:
[2] => Array
(
[PropertyType] => Array
(
[Guid] =>
[DataType] => Text
[Name] => diam-mm
[Unit] =>
)
[BooleanValue] =>
[DateTimeValue] =>
[NumericValue] =>
[TextValue] => 400
[XmlValue] =>
[UrlValue] => 400
)
[3] => Array
(
[PropertyType] => Array
(
[Guid] =>
[DataType] => Text
[Name] => lengte-mm
[Unit] =>
)
[BooleanValue] =>
[DateTimeValue] =>
[NumericValue] =>
[TextValue] => 2000
[XmlValue] =>
[UrlValue] => 2000
)
<?php
for ($i=0; $i <count($array) ; $i++) {
if($array[$i]['PropertyType']['Name']=="diam-mm"){
// your code
}
}
?>
If you want to check if an array key matches a value you can do so using simple variable assignment. However you would need to loop through each array index item and enumarate the loop based on it's iteration.
To create the loop I would suggest using count to count the amount of items in the array. We will assign the result to a variable :
$count = count($my_array);
Do keep in mind that count only counts the number of items based on their actual count, not their array index. This means that an array with indexes starting from zero which has an index of 0-30 would return 31 as the result of count because count counted the zero index as an actual count value.
To fix this we need to subtract 1 from the result of count :
$count = $count - 1;
Then we can use the count as the number of repeats in a for loop. Where the variable $i represents the iteration that the loop is going through :
//Loop through each array index
for($i=0; $i <= $count; $i++){
//Assign the value of the array key to a variable
$value = $my_array[$i]['PropertyType']['Name'];
//Check if result string contains diam-mm
if(str_contains($value, 'diam-mm'){
echo 'The value matches!';
} else{
echo 'The value does not match!';
}
}
Try this function, i hope this answer your question...
function array_recursive_search_key_map($needle, $haystack) {
foreach($haystack as $first_level_key=>$value) {
if ($needle === $value) {
return array($first_level_key);
} elseif (is_array($value)) {
$callback = $this->array_recursive_search_key_map($needle, $value);
if ($callback) {
return array_merge(array($first_level_key), $callback);
}
}
}
return false;
}
How to use
$yourValue = "diam-mm";
$array_keymap = array_recursive_search_key_map($yourValue, $yourArray);
var_dump($array_keymap);
Output
Array
(
[0] => 0
[1] => PropertyType
[2] => Name
)

How to skip iteration in foreach inside foreach

I have an array of values, and i want to insert the values to another array but with an if condition, if the "if" is true I want to skip the iteration.
Code:
$array=array(array(1=>11,2=>22,3=>23,4=>44,5=>55));
$insert=array();
foreach($array as $k1=>$v1)
{
foreach($v1 as $k2=>$v2)
{
if($v2==23)
{
break;
}
}
$insert[]=$v1;
}
final result should look like that
Array
(
[0] => Array
(
[1] => 11
[2] => 22
[3] => 44
[4] => 55
)
)
I tried using: break,return,continue...
Thanks
There are a few ways to do this. You can loop over the outer array and use array_filter on the inner array to remove where the value is 23 like this (IMO preferred; this also uses an array of $dontWant numbers so it is easier to add or change numbers later):
<?php
$array = array(array(1=>11,2=>22,3=>23,4=>44,5=>55));
$insert = array();
//array of numbers you don't want
$dontWant = array(23);
//loop over outer array
foreach($array as $subArray){
//add to $insert a filtered array
//subArray is filtered to remove where value is in $dontWant
$insert[] = array_filter($subArray, function($val) uses ($dontWant) {
//returns true if the value is not in the array of numbers we dont want
return !in_array($val, $dontWant);
});
}
//display final array
echo '<pre>'.print_r($insert,1).'</pre>';
Or you can reference the first key to add to a sub array in $insert like (which is a little more like what your code is trying to do and show that you are not too far off):
<?php
$array = array(array(1=>11,2=>22,3=>23,4=>44,5=>55));
$insert = array();
//loop over outer array
foreach($array as $k1=>$v1){
//add an empty array to $insert
$insert[$k1] = array();
//loop over inner array
foreach($v1 as $k2=>$v2){
//if the inner array value is not 23
if($v2 != 23){
//add to inner array in insert
$insert[$k1][] = $v2;
}
}
}
//display the result
echo '<pre>'.print_r($insert,1).'</pre>';
Both of these methods would produce the same result. IMO using array_filter is the preferred method, but the second method might be a little easier to understand for someone new to programming.
Why don't you just try it like this?
foreach($v1 as $k2=>$v2)
{
if($v2!=23)
{
$insert[]=$v2;
}
}
EDIT:
Explanation: You check with the if($v2!=23) if the value of the variable $v2 is not equal to (that is the != sign) any given number that stands after the inequality operator, and if so, it will insert that value to the array $insert.
I hope it is clear now.
Sorry, I've written $v1 instead of $v2, the code should work now.
To add variants :)
$array=array(array(1=>11,2=>22,3=>23,4=>44,5=>55));
$insert=array();
foreach($array as $a)
{
while (($i = array_search(23, $a)) !== false)
{ unset($a[$i]); sort($a); }
$insert[] = $a;
}
print_r($a);
result:
Array ( [0] => Array ( [0] => 11 [1] => 22 [2] => 44 [3] => 55 ) )

How to conditionally merge a multi-dimensional array

I have a multi-dimensional array:
Array
(
[10] => Array
(
[from] => Jack
[to] => Terry
[Bribe] => 0
[Joke_Payment] => 0
[Corrupt_Support] => 1
[Legitimate_Support] => 0
[Obfuscation] => 1
[Legal_Enforcement] => 0
[Whistleblower] => 0
)
[11] => Array
(
[from] => Terry
[to] => Jack
[Bribe] => 0
[Joke_Payment] => 0
[Corrupt_Support] => 1
[Legitimate_Support] => 0
[Obfuscation] => 0
[Legal_Enforcement] => 1
[Whistleblower] => 0
)
)
I want to update the above array to like this: have a 1 (going from from to to) and a -1 for the opposite direction, a 2 signify for "both directions.
Array ( [10] => Array
(
[from] => Jack
[to] => Terry
[Bribe] => 0
[Joke_Payment] => 0
[Corrupt_Support] => 2
[Legitimate_Support] => 0
[Obfuscation] => 1
[Legal_Enforcement] => -1
[Whistleblower] => 0
) }
How can I firstly calculate their intersect and then update the original array?
They will have the same amount to keys, and when from matches to, and to matches from element, I want to combine these two arrays into one. A '1' is used to indicate that the property relates in the from to to direction, and a -1 indicates that the property goes in the reverse direction (from to to from).
My current code is:
$fileRelation = explode("\r", $end);
$rowsRelation = array_map('str_getcsv', $fileRelation);
$headerRelation = array_shift($rowsRelation);
$csvArrRelation = array();
$countR = count($headerRelation);
foreach ($rowsRelation as $key => &$row) {
$index = 2;$sum = 0;$sumArr = array();
while ($index < $countR) {
if ($row[$index]>0) {
$sumArr[$sum]=$index; //store row $headerRelation index
$sum++;
}
$index++;
}
if($sum > 0){ //remove element if no relationship exist
foreach ($csvArrRelation as $k => $a) {
if (in_array($row[0], $csvArrRelation[$k]) && in_array($row[1], $csvArrRelation[$k])){
$p = array_values($a);$i = 2;$cp= count($p);
while($i < $cp ){
if($row[$i] == $p[$i]){
$a[$headerRelation[$i]] += $row[$i];
}else{
$a[$headerRelation[$i]] -= $row[$i];
}
$i++;
}
unset( $rowsRelation[$key] );
}
}
$csvArrRelation[] = array_combine($headerRelation, $row);
}
}
I won't write this for you, but here is a good start:
$newRelations = [];
$deletions = [];
foreach ($rowsRelation as $key1 => $row1)
{
foreach ($rowsRelation as $key2 => $row2)
{
// Don't compare with self
if ($key1 != $key2)
{
// Have we found a reverse match?
if (
$row1['from'] == $row2['to'] &&
$row1['to'] == $row2['from']
)
{
$newRelations[] = myMerge($row1, $row2);
$deletions[] = $key1;
$deletions[] = $key2;
}
}
}
}
// Delete old rows
foreach ($deletions as $deleteKey)
{
unset($rowsRelation[$deleteKey]);
}
// Add in new rows
$rowsRelation = array_merge($rowsRelation, $newRelations);
function myMerge(array $row1, array $row2)
{
// todo
}
My strategy is to compare each row with every other, and if a reverse match is found, we know a merge is due. To avoid corrupting the foreach loops, I add the new array value to a different array, and log which keys I wish to delete from the original. These are then merged/deleted after the work is done.
I assume this is some kind of game, so let's call "player 1" the player whose name appears in "from" field and "player 2" the one whose name appears in "to" field.
According to what I understood, you consider player 1's values positive and player 2's negative. Then you sum both values in "from player 1 to player 2" record and discard "from player 2 to player 1" record.
According to that rule, Corrupt_Support should end up with a value of 0, not 2.
Basically, after merging your records, you will not be able to tell the difference between no actions at all and actions that have cancelled each other.
Besides, there is no rule to chose a "winner", i.e. which "from" player will be retained, leading to potentially impractical results.
If you have 3 players Abe, Bob and Cal, you can end up with any possible order, for instance
["Abe vs Bob", "Bob vs Cal" and "Cal vs Abe"] or
["Abe vs Bob", "Abe vs Cal" and "Cal vs Bob"].
Looking up actions for Bob will be rather problematic in the latter case.
Now if you still want to do that, here is a way that takes advantage of PHP hash tables to speed up the merge and choses the "winner" according to alphabetic order:
// use "from player 1 to player 2" relation as key
foreach ($relations as $r) $relation_pairs[$r['from'].'+'.$r['to']] = $r;
// pick the "winners" according to alphabetic order
ksort ($relation_pairs);
// merge relations
while (list($k,$r) = each($relation_pairs)) // this will take elements deletion into account immediately, contrary to foreach
{
$symetric = $r['to'].'+'.$r['from'];
if (isset($relation_pairs[$symetric])) // found a symetric relation
{
foreach ($relation_pairs[$symetric] as $field=>$value) // combine all numeric fields
if (is_numeric ($value))
$relation_pairs[$k][$field] -= $value;
unset ($relation_pairs[$symetric]); // get rid of symetric relation
}
}
$compressed_relations = array_values ($relation_pairs); // get rid of keys

How to compare 2 arrays for common items in PHP?

I am writing a script to compare the achievements of one player to another in a game. In each of the arrays the id and timestamp will match up on some entries. I have included a sample of one of the start of the 2 separate arrays:
Array
(
[0] => Array
(
[id] => 8213
[timestamp] => 1384420404000
[url] => http://www.wowhead.com/achievement=8213&who=Azramon&when=1384420404000
[name] => Friends In Places Higher Yet
)
[1] => Array
(
[id] => 6460
[timestamp] => 1384156380000
[url] => http://www.wowhead.com/achievement=6460&who=Azramon&when=1384156380000
[name] => Hydrophobia
)
I want to find all of the array items where the id and timestamp match. I have looked into array_intersect but I don't think this is what I am looking for as it will only find items when the entries are identical. Any help much appreciated.
You may use array_intersect_assoc function.
Try something like this:
<?php
$key_match = Array();
//Loop first array
foreach($array as $key => $element){
//Compare to second array
if($element == $array2[$key]){
//Store matching keys
$key_match[] = $key;
}
}
?>
$key_match will be an array with all matching keys.
(I'm at work and havn't had time to test the code)
Hope it helps
EDIT:
Fully working example below:
<?php
$a1["t"] = "123";
$a1["b"] = "124";
$a1["3"] = "125";
$a2["t"] = "123";
$a2["b"] = "124";
$a2["3"] = "115";
$key_match = Array();
//Loop first array
foreach($a1 as $key => $element){
//Compare to second array
if($element == $a2[$key]){
//Store matching keys
$key_match[] = $key;
}
}
var_dump($key_match);
?>
If you want to go on an exploration of array callback functions, take a look at array_uintersect. It's like array_intersect except you specify a function to use for the comparison. This means you can write your own.
Unfortunately, you need to implement a function that returns -1, 0 or 1 based on less than, same as, greater than, so you need more code. But I suspect that it'll be the most efficient way of doing what you're looking for.
function compareArrays( $compareArray1, $compareArray2 ) {
if ( $compareArray1['id'] == $compareArray2['id'] && $compareArray1['timestamp'] == $compareArray2['timestamp'] ) {
return 0;
}
if ( $compareArray1['id'] < $compareArray2['id'] ) {
return -1;
}
if ( $compareArray1['id'] > $compareArray2['id'] ) {
return 1;
}
if ( $compareArray1['timestamp'] < $compareArray2['timestamp'] ) {
return -1;
}
if ( $compareArray1['timestamp'] > $compareArray2['timestamp'] ) {
return 1;
}
}
var_dump( array_uintersect( $array1, $array2, "compareArrays") );

Insert value from one array to another and keep their keys

I have 2 Arrays :
Array
(
[1] => image1
[4] => image2
)
Array
(
[0] => title 1
[2] => title 2
[3] => title 3
)
I just want to merge these arrays and KEEP their key ([1] => image1 will also be at [1] in the new array)
Any idea please ? Thanks !
That should work :)
foreach ($array2 as $key => $value)
{
$array1[$key] = $value;
}
The keys & values from array2 will be appended at the end. If your array is just numeric, you can bring it to the right order with array_sort().
I think this function works. You have to use only numeric keys tough
$array1;
$array2;
array_weird_merge($array1, $array2){
$result = array();
//get the keys of each array
$keys1 = array_keys($array1);
$kesy2 = array_keys($array2);
//get the max keys of the 2 arrays
$max = max($key1, $key2);
//we go trough all the possible values
for ($i=0; $i<$max;$i++){
//if the array 1 has an element in the
//$i position, we put it in the result
//if not, then we check in the second
//array. (we give priority to the array
//that comes first)
if(isset($array1[$i])){
$result[$i] = $array1[$i];
}else if(isset($array2[$i])){
$result[$i] = $array2[$i];
}
}
return $result;
}

Categories