I need to get the last entries of all duplicate records in an array. How can I do this in php
example data
Input Array
Array
(
[0] => Array ( [0] => A )
[1] => Array ( [0] => A )
[2] => Array ( [0] => B )
[3] => Array ( [0] => C )
[4] => Array ( [0] => C )
[5] => Array ( [0] => D )
[6] => Array ( [0] => F )
[7] => Array ( [0] => F )
)
Result output List 1 should only contain last entry of all duplicate records
Array
(
[1] => Array ( [0] => A )
[4] => Array ( [0] => C )
[7] => Array ( [0] => F )
)
Result output List 2 Should contain all other enteries.
Array
(
[0] => Array ( [0] => A )
[2] => Array ( [0] => B )
[3] => Array ( [0] => C )
[5] => Array ( [0] => D )
[6] => Array ( [0] => F )
)
Not sure if you wanted it this way, but you can try this:
<?php
$array = array
(
0 => array ( 0 => 'A' ),
1 => array ( 0 => 'A' ),
2 => array ( 0 => 'B' ),
3 => array ( 0 => 'C' ),
4 => array ( 0 => 'C' ),
5 => array ( 0 => 'D' ),
6 => array ( 0 => 'F' ),
7 => array ( 0 => 'F' )
);
foreach ($array as $k => $v){
echo $k . " --> ";
if (is_array($v)){
foreach($v as $k1=>$v1){
echo $v1."<br />";
$new_array[$k]=$v1;
}
}else{
echo $v."<br />";
}
}
echo "<br />";
// Restructured array
print_r($new_array);
echo "<br />";
// Duplicates
print_r(get_duplicates($new_array));
echo "<br />";
// All entries
print_r(array_unique($new_array));
// Function to get duplicates
function get_duplicates( $array ) {
return array_unique( array_diff_assoc( $array, array_unique( $array ) ) );
}
?>
output would be:
//original
Array ( [0] => A [1] => A [2] => B [3] => C [4] => C [5] => D [6] => F [7] => F )
//dupes
Array ( [1] => A [4] => C [7] => F )
//all entries
Array ( [0] => A [2] => B [3] => C [5] => D [6] => F )
typed this up quickly. haven't had a chance to test it yet, but should do the trick.
note that the inner loop is non-optimal -- it could be improved a lot, especially if the data is known to be sorted (as in the example data), but you didn't specify that, so I haven't assumed it.
<?php
$output_dups = array();
$output_remainder = array();
foreach($input_array as $key=>$data) {
$dup_found = false;
foreach($input_array as $key2=>$data2) {
if($key < $key2 && $data===$data2) { $dup_found = true; }
}
if($dup_found) { $output_dups[] = $data; } else { $output_remainder[] = $data; }
}
?>
//My implementation is something like this.
set_time_limit (1500) ;
ini_set("memory_limit","128M");
$fileName = "_one";
$objScan = new scanCSV();
$objScan->setCSVFileName($fileName);
$objScan->loadCsvFile();
$objScan->separateDuplicateFromUniq();
$objScan->process();
class scanCSV
{
private $_csvFile = NULL;
private $_arrayListAll = NULL;
private $_allDuplicateRec = NULL;
private $_uniqueRec = NULL;
function setCSVFileName($fileName){
$this->_csvFile = $fileName;
}
//-----------------------------------------------------------------------
function loadCsvFile()
{
$arrayListAll = array();
if (($handle = fopen($this->_csvFile . ".csv", "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
$arrayListAll[] = $data;
}
}
$this->_arrayListAll = $arrayListAll;
}
//-----------------------------------------------------------------------
public function separateDuplicateFromUniq(){
$allDuplicateRec = array();
$uniqueRec = array();
foreach($this->_arrayListAll as $data){
if ($this->getcount($this->_arrayListAll, $data) > 1)
$allDuplicateRec[] = $data;
else
$uniqueRec[] = $data;
}
$this->_allDuplicateRec = $allDuplicateRec;
$this->_uniqueRec = $uniqueRec;
}
//-----------------------------------------------------------------------
public function process (){
$uniq = $this->removeDuplicate ($this->_allDuplicateRec);
$this->writeCSVFile ($this->_csvFile . "A.csv", $uniq);
$restofEntries = $this->removeLastEntries ($this->_arrayListAll, $uniq);
$this->writeCSVFile ($this->_csvFile . "B.csv", $restofEntries);
}
//-----------------------------------------------------------------------
function removeDuplicate ($allDuplicateRec)
{
foreach ($allDuplicateRec as $k => $v)
if ( $this->getcount($allDuplicateRec, $v) > 1 )
unset($allDuplicateRec[$k]);
return $allDuplicateRec;
}
//-----------------------------------------------------------------------
function removeLastEntries ($arrayListAll, $uniq){
foreach ($uniq as $entry)
if(in_array($entry, $arrayListAll))
unset($arrayListAll[array_search($entry, $arrayListAll)]);
return $arrayListAll;
}
//-----------------------------------------------------------------------
function getcount($arrayList1, $data){
$address = $data[2];
$count =0;
foreach ($arrayList1 as $dt)
if ($address == $dt[2])
$count++;
return $count;
}
//-----------------------------------------------------------------------
function writeCSVFile ($fileName, $data){
$fp = fopen($fileName, 'w');
foreach ($data as $k=>$fields)
fputcsv($fp, $fields);
fclose($fp);
}
//-----------------------------------------------------------------------
} // end of scan Optimized
Related
I have nested multidimensional arrays that may be 2 or 3 levels deep. Inside it I may or may not have list arrray. I need to loop over the array:
Array
(
[0] => Array
(
[id] => 1
[name] => cat_name_1
[list] => Array
(
[1] => swgdgbdg
[2] => xcbcxb
)
)
[1] => Array
(
[id] => 3
[name] => cat_name_3
[list] => Array
(
[0] => Array
(
[id] => 1
[name] => cat_name_1
[list] => Array
(
[1] => 543h54h
[2] => 54hrhhfr2
)
)
[1] => Array
(
[id] => 2
[name] => cat_name_2
[list] => Array
(
[1] => eherfherh
[2] => 4564642
)
)
[2] => Array
(
[1] => erggb45yt
[2] => jyuk768k
)
[3] => Array
(
[1] => sdgsdgsdg
[2] => 4tg34g34g
)
)
)
and store the following in another array:
array (
0 => array (
[1] => swgdgbdg
[2] => xcbcxb
) ,
1 => array(
[1] => 543h54h
[2] => 54hrhhfr2
) ,
2 => array(
[1] => eherfherh
[2] => 4564642
),
3 => array(
[1] => erggb45yt
[2] => jyuk768k
),
4 => array(
[1] => sdgsdgsdg
[2] => 4tg34g34g
)
);
You can use array_walk_recursive() to get the key 1,2 and are not array element, like this, check the live demo here.
$result = [];
$temp = [];
array_walk_recursive($array, function($v, $k) use(&$result, &$temp){
if($k == 1)
$temp[$k] = $v;
if($k == 2)
{
$temp[$k] = $v;
$result[] = $temp;
}
});
print_r($result);
Edit for unfixed length and unordered index, live demo.
Extend the array_walk_recursive() with a third parameter for the callfunction to indicate if it's at the start of an subarray.
$result = [];
$temp = [];
$length = 0;
uarray_walk_recursive($array, function($v, $k, $f) use(&$result, &$temp, &$length){
if(is_numeric($k)) {
if($f && $length != 0) {
$result[] = $temp;
$length = 0;
$temp = [];
}
$temp[$k] = $v;
$length++;
}
});
$result[] = $temp;
print_r($result);
function uarray_walk_recursive(&$input, $funcname)
{
if (!is_callable($funcname)) {
if (is_array($funcname)) {
$funcname = $funcname[0] . '::' . $funcname[1];
}
user_error('uarray_walk_recursive() Not a valid callback ' . $user_func,
E_USER_WARNING);
return;
}
if (!is_array($input)) {
user_error('uarray_walk_recursive() The argument should be an array',
E_USER_WARNING);
return;
}
$args = func_get_args();
$flag = true;
foreach ($input as $key => $item) {
if (is_array($item)) {
$args[2] = false;
$flag = true;
uarray_walk_recursive($item, $funcname, $args);
$input[$key] = $item;
} else {
$args[2] = $flag;
$flag = false;
$args[0] = &$item;
$args[1] = &$key;
call_user_func_array($funcname, $args);
$input[$key] = $item;
}
}
}
PseudoCode
function getSomething(var arr)
{
flag = 0;
output = []
for( i = 0 to arr.length)
{
check arr[i] is array,
if yes,then flag = 1 and output.add(getSomething(arr[i]))
if not, continue
}
if flag =0,then return arr
else return output;
}
I have an array a bit like:
Array (
[1] => Array
(
[1] => 21
[2] => 3
[0] => Analyst
)
[2] => Array
(
[1] => 47
[2] => 8
[0] => Catalysis
)
[3] => Array
(
[1] => 1
[2] => 0
[0] => Biomaterials
)
[4] => Array
(
[3] => 12
[4] => 2
[0] => Analyst
)
[5] => Array
(
[5] => 12
[6] => 2
[0] => Analyst
)
...
However I would like to renumber those entries with the same [0] value so that I end up with
[1] => Array
(
[1] => 21
[2] => 3
[3] => 12
[4] => 2
[5] => 12
[6] => 2
[0] => Analyst
)
So far I've tried getting the [0] values out of the $results array by putting them in their own array and saying if you're already there then add [3] and [4] to where [1] and [2] are in a new array but it's not working.
$final = array();
$jArray = array();
foreach($results as $key => $result) {
if(!in_array($result[0],$jArray) && !empty($result[0])) {
$jArray[$i] = $result[0];
$i++;
}
}
for($x = 0; $x < count($results); $x++) {
$k = array_search($results[$x][0],$jArray);
if(!isset($results[$x][1]))
$final[$k][1] = $results[$x][1];
if(!isset($results[$x][2]))
$final[$k][2] = $results[$x][2];
if(!isset($results[$x][3]))
$final[$k][3] = $results[$x][3];
if(!isset($results[$x][4]))
$final[$k][4] = $results[$x][4];
if(!isset($results[$x][5]))
$final[$k][5] = $results[$x][5];
if(!isset($results[$x][6]))
$final[$k][6] = $results[$x][6];
}
Any simpler ways of doing this?
You can do this way...
$new_arr=array();
$arkeys = array_unique(array_map(function ($v){ return $v[0];},$arr));
foreach($arr as $k=>$arr1)
{
$new_arr[$arr1[0]][]=array_slice($arr1,0,count($arr1)-1);
}
foreach($arkeys as $v)
{
$new_arr[$v] = call_user_func_array('array_merge', $new_arr[$v]);
}
print_r($new_arr);
OUTPUT :
Array
(
[Analyst] => Array
(
[0] => 21
[1] => 3
[2] => 12
[3] => 2
[4] => 12
[5] => 2
)
[Catalysis] => Array
(
[0] => 47
[1] => 8
)
[Biomaterials] => Array
(
[0] => 1
[1] => 0
)
)
Working Demo
If you just want to group by the first element of the sub array, a single loop is enough:
$result = array();
foreach ($array as $sub_arr) {
$key = $sub_arr[0];
unset($sub_arr[0]);
if (!isset($result[$key])) {
$result[$key] = array();
}
$result[$key] += $sub_arr;
}
Here
$final = array();
foreach($results as $key => $result) {
if (!in_array($result[0], array_keys( $final ) ) && !empty($result[0])) {
$final[$result[0]] = array( $result[0] );
}
foreach($result as $k => $v) {
if ($k != 0 && isset($v)) {
$final[$result[0]][$k] = $v;
}
}
}
I have a function that's supposed to take in an array of arrays, and split it into an array of arrays of 100 items each. The problem is that when I execute it, in this case, passing it 1137 items, the return array, has 12 arrays, all empty except for the last one.
Here's the code:
$names_to_fetch_from_twitter = array (
array('screen_name' => 'acme', 'profiles_rownum' => 1, 'screen_name_rownum' => 1),
array('screen_name' => 'acme1', 'profiles_rownum' => 2, 'screen_name_rownum' => 2),
array('screen_name' => 'acme2', 'profiles_rownum' => 3, 'screen_name_rownum' => 3),
array('screen_name' => 'acme3', 'profiles_rownum' => 4, 'screen_name_rownum' => 4),
array('screen_name' => 'acme4', 'profiles_rownum' => 5, 'screen_name_rownum' => 5)
);
$names_to_fetch_from_twitter_organized = split_into_blokcs_of_3 ($names_to_fetch_from_twitter);
echo '<pre>';
print_r($names_to_fetch_from_twitter_organized);
echo '</pre>';
function split_into_blokcs_of_3 ($names_to_fetch_from_twitter)
{
$names_to_fetch_from_twitter_organized = array();
$count = 1;
$screen_names = array();
$profiles_row_nums = array();
$screen_name_rownums = array();
foreach ($names_to_fetch_from_twitter as $name_to_fetch_from_twitter) {
$screen_names[] = $name_to_fetch_from_twitter['screen_name'];
$profiles_row_nums[] = $name_to_fetch_from_twitter['profiles_rownum'];
$screen_name_rownums[] = $name_to_fetch_from_twitter['screen_name_rownum'];
$count++;
if ($count > 3) {
$count = 1;
$screen_names = array();
$profiles_row_nums = array();
$screen_name_rownums = array();
$names_to_fetch_from_twitter_organized[] =
package_into_array($screen_names,$profiles_row_nums,$screen_name_rownums,$names_to_fetch_from_twitter_organized);
}
}
if ($count > 1) {
$names_to_fetch_from_twitter_organized[] =
package_into_array($screen_names,$profiles_row_nums,$screen_name_rownums,$names_to_fetch_from_twitter_organized);
}
return $names_to_fetch_from_twitter_organized;
}
function package_into_array($screen_names,$profiles_row_nums,$screen_name_rownums,$names_to_fetch_from_twitter_organized)
{
$names_to_fetch_from_twitter_organized[] = array (
'screen_names' => implode (',',$screen_names),
'profiles_row_nums' => $profiles_row_nums,
'screen_name_rownums' => $screen_name_rownums
);
return $names_to_fetch_from_twitter_organized;
}
Here's the output:
Array
(
[0] => Array
(
[0] => Array
(
[screen_names] =>
[profiles_row_nums] => Array
(
)
[screen_name_rownums] => Array
(
)
)
)
[1] => Array
(
[0] => Array
(
[0] => Array
(
[screen_names] =>
[profiles_row_nums] => Array
(
)
[screen_name_rownums] => Array
(
)
)
)
[1] => Array
(
[screen_names] => acme3,acme4
[profiles_row_nums] => Array
(
[0] => 4
[1] => 5
)
[screen_name_rownums] => Array
(
[0] => 4
[1] => 5
)
)
)
)
When I'm expecting the following:
Array
(
[0] => Array
(
[screen_names] => acme1,acme2,acme3
[profiles_row_nums] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
[screen_name_rownums] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
)
[1] => Array
(
[screen_names] => acme4,acme5
[profiles_row_nums] => Array
(
[0] => 1
[1] => 2
)
[screen_name_rownums] => Array
(
[0] => 1
[1] => 2
)
)
)
Any ideas?
Solution:
I had a couple of errors:
I was resetting the arrays before I included them in the master array
I was incrementing the array both in the main function and the helper function.
Here's the correct code:
function split_into_blokcs_of_3 ($names_to_fetch_from_twitter)
{
$names_to_fetch_from_twitter_organized = array();
$count = 1;
$screen_names = array();
$profiles_row_nums = array();
$screen_name_rownums = array();
foreach ($names_to_fetch_from_twitter as $name_to_fetch_from_twitter) {
$screen_names[] = $name_to_fetch_from_twitter['screen_name'];
$profiles_row_nums[] = $name_to_fetch_from_twitter['profiles_rownum'];
$screen_name_rownums[] = $name_to_fetch_from_twitter['screen_name_rownum'];
$count++;
if ($count > 3) {
$names_to_fetch_from_twitter_organized =
package_into_array($screen_names,$profiles_row_nums,$screen_name_rownums,$names_to_fetch_from_twitter_organized);
$count = 1;
$screen_names = array();
$profiles_row_nums = array();
$screen_name_rownums = array();
}
}
if ($count > 1) {
$names_to_fetch_from_twitter_organized =
package_into_array($screen_names,$profiles_row_nums,$screen_name_rownums,$names_to_fetch_from_twitter_organized);
}
return $names_to_fetch_from_twitter_organized;
}
I think you might be assuming that a new array is created inside of the if($count > 3) block.
You might try adding new array() there instead of just array but that should overwrite what was there previously.
How to arrange this array by last inner index ( 0, 1, 2 ) and get the value of the last inner index as the value of each second index:
Array
(
[text] => Array
(
[grid] => Array
(
[0] => 3
[1] => 4
[2] => 5
)
[image] => Array
(
[0] =>
[1] =>
[2] =>
)
[align] => Array
(
[0] => left
[1] => right
[2] => left
)
[title] => Array
(
[0] =>
[1] =>
[2] =>
)
[content] => Array
(
[0] =>
[1] =>
[2] =>
)
)
)
And have the results as below:
Array
(
[text] => Array
(
[0] => Array
(
[grid] => 3
[image] =>
[align] => left
[title] =>
[content] =>
)
[1] => Array
(
[grid] => 4
[image] =>
[align] => right
[title] =>
[content] =>
)
[2] => Array
(
[grid] => 5
[image] =>
[align] => left
[title] =>
[content] =>
)
)
)
This will do the work
function restructure($arr){
$newArr = array();
foreach($arr as $k => $v){
foreach($v as $k1 => $v1){
foreach($v1 as $k2 => $v2){
$newArr[$k][$k2][$k1] = $v2;
}
}
}
return $newArr;
}
As SiGanteng suggested, i dont see other ways than a for/foreach loop:
function buildArray($source, $key = false)
{
// Build the new array
$new_array = array();
// Define groups
$groups = $key === false ? array_keys($source) : array($key);
foreach($groups AS $group)
{
// Get the keys
$keys = array_keys($array[$group]);
// Count the values
$num_entries = count($array[$group][$keys[0]]);
for($i = 0; $i < $num_entries; $i++)
{
foreach($keys AS $key)
{
$new_array[$group][$i][$key] = $array[$group][$key][$i];
}
}
}
return $new_array;
}
This allow you to define the key you need to build; If not specified, the function build the array for every key.
This should work.
function formatit($arr) {
$new = array();
foreach($arr as $k=>$v) {
foreach($v as $k1=>$v1) {
$new[$k1][$k] = $v1;
}
}
return $new;
}
Tested. Call it as
$arr['text'] = formatit($arr['text']);
http://ideone.com/rPzuR
I have tried to make a function that iterates through the following array to flatten it and add parent id to children, where applicable. I just can't make it work, so I hope that anyone here has an idea of what to do:
Here's the starting point:
Array
(
[0] => Array (
[id] => 1
[children] => array (
[id] => 2
[children] => Array (
[0] => Array (
[id] => 3
)
)
)
)
The expected result :
Array (
[0] => array (
[id] => 1
)
[1] => array (
[id] => 2
)
[2] => array (
[id] => 3,
[parent] => 2
)
)
Hope that anyone can point me in the right direction. Thanks a lot!
Solution (Thanks to Oli!):
$output = array();
function dejigg($in) {
global $output;
if (!isset($in['children'])) {
$in['children'] = array();
}
$kids = $in['children'] or array();
unset($in['children']);
if (!isset($in['parent'])) {
$in['parent'] = 0; // Not neccessary but makes the top node's parent 0.
}
$output[] = $in;
foreach ($kids as $child) {
$child['parent'] = $in['id'];
dejigg($child); // recurse
}
return $output;
}
foreach ($array as $parent) {
$output[] = dejigg($parent);
}
$array = $output;
print("<pre>".print_r($array,true)."</pre>");
I've tested it this time. This does work!
$input = array( array('id' => 1, 'children'=>array( array('id'=>2, 'children'=>array( array('id'=>3) ) ) ) ) );
$output = [];
function dejigg($in) {
global $output;
$kids = $in['children'] or array();
unset($in['children']);
$output[] = $in;
foreach ($kids as $child) {
$child['parent'] = $in['id'];
dejigg($child); // recurse
}
}
foreach ($input as $parent)
dejigg($parent);
print_r($output);
And it returns:
Array
(
[0] => Array
(
[id] => 1
)
[1] => Array
(
[id] => 2
[parent] => 1
)
[2] => Array
(
[id] => 3
[parent] => 2
)
)