I have two arrays named rows and contacts.
The first array rows is like :
Array
(
[0] => email#gmail.com
[1] => test#gmail.com
[2] => tester#gmail.com
[3] => vin#gmail.com
)
The second array contacts is as :
Array
(
[test#gmail.com] => test#gmail.com
[ram#gmail.com] => Ram
[vin#gmail.com] => Vinay
[man_test#yahoo.com] => Manoj
[homan#rediffmail.com] => Homan
)
What I want is the contacts array to be as :
Array
(
[ram#gmail.com] => Ram
[man_test#yahoo.com] => Manoj
[homan#rediffmail.com] => Homan
)
Edit
I tried some functions like array_diff(), array_keys() etc. but they are not giving me the desired output, may be I am not able to use them correctly....!
I don't want to use loop for this purpose because the given arrays are only sample data but in real they are very huge.
Please help.....
Thanks in Advance.....
Another way:
$contacts = array_diff_key($contacts, array_flip($rows));
Assuming I understand the question correctly, you could do that:
for ($i = 0; $i < count($rows); $i++) {
$s = $rows[$i];
unset($contacts[$s]);
}
foreach ($contacts as $email => $name) {
if (!in_array($email, $rows)) {
$contact[$email] = $name;
}
}
The new array is $contact, not $contacts, as your question asked for before you edited it.
As Felix Kling and Dan Grossman's answers will work on the examples you have shown, you probably have whitespace issues like newlines in your data, especially if you have extracted it from a file. So, extending Felix's answer:
$contacts = array_diff_key(array_map('trim', $contacts), array_flip(array_map('trim', $rows)));
You could probably make it more efficient by constructing your data correctly in the first place, but this should do the trick.
http://codepad.org/RIvLbyJy
Related
This question already has answers here:
How to extract data from csv file in PHP
(13 answers)
Closed 1 year ago.
Apologies if this question is close to others. I have tried every solution to accomplish something simple with nothing but failure. :-(
I want the keys from array one to be assigned as keys to array two.
$demos_keys = array_keys($demos);
//$c = array_combine($demos_keys, $csvdata); produces "FALSE"
//$c = $demos_keys + $csvdata; simply adds the arrays but doesn't assign keys
So then I tried to loop through each element to assign the keys manually - to no avail!
foreach ($csvdata as $row){
for($i = 0; $i<count($demo_keys); $i++) {
$csvdata[$demo_keys[$i]]=$row[$i];
}
}
demos_keys:
lastname":"lastname","email":"email","d1":"phone","d2":"status"
csvdata:
"Dryer,fdryer#email.com,Backfield,North\r","Harris,fharris#email.com,Corp,South\r",etc.
I feel the csvdata array is wonky somehow. Every thing say it is an array with about 1000 rows, but the carriage return at the end of the last element is troubling me. I thought I'd deal with it later.
What else can I try!? Thank you all for any contributions!
It looks like each row of your CSV data has not been parsed into separate variables (are you reading it from a file using fgets or file instead of fgetcsv?). So you need to split it before you can combine it with the keys from $demos_keys. Something like this should work:
$demos_keys = array("lastname","email","d1","d2");
$csvdata = array("Dryer,fdryer#email.com,Backfield,North\r","Harris,fharris#email.com,Corp,South\r");
$result = array();
foreach ($csvdata as $row) {
$data = explode(',', trim($row));
$result[] = array_combine($demos_keys, $data);
}
print_r($result);
Output:
Array
(
[0] => Array
(
[lastname] => Dryer
[email] => fdryer#email.com
[d1] => Backfield
[d2] => North
)
[1] => Array
(
[lastname] => Harris
[email] => fharris#email.com
[d1] => Corp
[d2] => South
)
)
Demo on 3v4l.org
I have a post array and need to create a new array format from this to store in database with batch insert. I have achieved it with the following code. But want a better solution (if any) to achieve my array. I wanted to eliminate the inner loop but did not get any solution. Please provide any suggestion on how can I achieve this.
Code to parse array:
if ($this->input->post()) {
foreach ($this->input->post() as $key => $value) {
$i = 0;
/* need to eliminate this loop */
foreach ($value as $k => $v) {
$postData[$i][$key] = $v;
$i++;
}
}
}
Input array:
Array
(
[category_id] => Array
(
[0] => 1
[1] => 4
)
[pay_type_id] => Array
(
[0] => 2
[1] => 5
)
[frequency_id] => Array
(
[0] => 3
[1] => 6
)
)
Output array;
Array
(
[0] => Array
(
[category_id] => 1
[pay_type_id] => 2
[frequency_id] => 3
)
[1] => Array
(
[category_id] => 4
[pay_type_id] => 5
[frequency_id] => 6
)
)
If you really want to, you can do this without loops at all:
$input = $this->input->post();
$keys = array_keys($input);
$postData = [
array_combine($keys, array_column($input, 0)),
array_combine($keys, array_column($input, 1)),
];
This will give the same $postData output as your example, assuming that the input only has keys 0 and 1 in the inner arrays, as it does in your example. If the number of possible elements in the inner arrays is unknown, then you may need to introduce a loop on that, but the secondary loop can still be avoided.
I had to use array_combine() as well as array_column() as array_column() on it's own does not preserve the named keys the your top level of your array.
Other solutions using array_map() or array_walk() may also exist.
However, while it's short and concise, it isn't exactly clear for a reader to understand what it's doing, so unless you document it clearly, you'll be creating a maintenance headache for yourself in the long term.
The double-loop is a more readily understandable solution, pretty standard, and won't cause you any issues. So while I've given you a solution, I would actually recommend just using the code you've got.
Because you have two arrays, a:"records" and b:"fields" in any case, theoretically, you need to have at least two loops to populate the "records" and "fields" inside a record. And, basically, this is not a bad approach or a problem.
If you really want just one loop, because of faith reasons, you need to put a hard-coded list of field assignments in first loop that populate the records.
The only way I can see to do it without a second array is like this:
$arr = array("category_id" => array(1, 4), "pay_type_id" => array(2, 5), "frequency_id" => array(3, 6));
foreach ($arr as $key => $value) {
$postData[0][$key] = $value[0];
$postData[1][$key] = $value[1];
}
print_r($postData);
But you lose flexibility with this approach, because you have to know in advance how many indexes there will be in the inner arrays. The only way to make it generic enough to cope with changes in data is to use an inner loop similar to how you did it originally.
There's nothing much wrong with your original code, it's a pretty standard and reasonable approach to changing the array format in this scenario. It shouldn't give you any particular performance issues, even with fairly large arrays, and there's not really any neater way to approach it.
As per your ouput you need second loop also. But yes you can eliminate use of $i you can use $k instead.
You can change your code as:
if ($this->input->post()) {
foreach ($this->input->post() as $key => $value) {
foreach ($value as $k => $v) {
$postData[$k][$key] = $v;
}
}
}
DEMO
I will try to explain the data I'm working with first, then I'll explain what I hope to do with the data, then I'll explain what I've tried so far. Hopefully someone can point me in the right direction.
What I'm working with:
I have an array containing survey responses. The first two items are the two answers for the first question and responses contains the number of people who selected those answers. The last three items are the three answers for the other question we asked.
Array
(
[0] => Array
(
[survey_id] => 123456789
[question_text] => Have you made any changes in how you use our product this year?
[d_answer_text] => No
[responses] => 92
)
[1] => Array
(
[survey_id] => 123456789
[question_text] => Have you made any changes in how you use our product this year?
[answer_text] => Yes
[responses] => 30
)
[2] => Array
(
[survey_id] => 123456789
[question_text] => How would you describe your interaction with our staff compared to prior years?
[answer_text] => Less Positive
[responses] => 14
)
[3] => Array
(
[survey_id] => 123456789
[question_text] => How would you describe your interaction with our staff compared to prior years?
[answer_text] => More Positive
[responses] => 35
)
[4] => Array
(
[survey_id] => 123456789
[question_text] => How would you describe your interaction with our staff compared to prior years?
[answer_text] => No Change
[responses] => 72
)
)
What I want to achieve:
I want to create an array where the question_text is used as the key (or I might grab the question_id and use it instead), use the answer_text as a key, with the responses as the value. It would look something like this:
Array
(
[Have you made any changes in how you use our product this year?] => Array
(
[No] => 92
[Yes] => 30
)
[How would you describe your interaction with our staff compared to prior years?] => Array
(
[Less Positive] => 14
[More Positive] => 35
[No Change] => 72
)
)
Here's what I've tried:
$response_array = array();
foreach($result_array as $value){
//$responses_array['Our question'] = array('answer 1'=>responses,'answer 2'=>responses);
$responses_array[$value['question_text']] = array($value['answer_text']=>$value['responses']);
}
This does not work because each loop will overwrite the value for $responses_array[$question]. This makes sense to me and I understand why it won't work.
My next thought was to try using array_merge().
$responses_array = array();
foreach($result as $value){
$question_text = $value['question_text'];
$answer_text = $value['answer_text'];
$responses = $value['responses'];
$responses_array[$question_text] = array_merge(array($responses_array[$question_text],$answer_text=>$responses));
}
I guess my logic was wrong because it looks like the array is nesting too much.
Array
(
[Have you made any changes in how you use our product this year?] => Array
(
[0] => Array
(
[0] =>
[No] => 92
)
[Yes] => 30
)
My problem with array_merge is that I don't have access to all answers for the question in each iteration of the foreach loop.
I want to design this in a way that allows it to scale up if we introduce more questions with different numbers of answers. How can this be solved?
Sounds like a reduce job
$response_array = array_reduce($result_array, function($carry, $item) {
$carry[$item['question_text']][$item['answer_text']] = $item['responses'];
return $carry;
}, []);
Demo ~ https://eval.in/687264
Update
Remove condition (see #Phil comment)
I think you are looking for something like that :
$output = [];
for($i = 0; $i < count($array); $i++) {
$output[$array[$i]['question_text']] [$array[$i]['answer_text']]= $array[$i]['responses'];
}
print_r($output);
Slightly different approach than the answer posted, more in tune with what you'v already tried. Try This:
$responses_array = array();
$sub_array = array();
$index = $result[0]['question_text'];
foreach($result as $value){
$question_text = $value['question_text'];
$answer_text = $value['answer_text'];
$responses = $value['responses'];
if (strcmp($index, $question_text) == 0) {
$sub_array[$answer_text] = $responses;
} else {
$index = $question_text;
$responses_array[$index] = $sub_array;
$sub_array = array();
}
}
Edit: Found my mistake, updated my answer slightly, hopefully this will work.
Edit 2: Working with example here: https://eval.in/687275
Ok so I have been struggling with this for hours now and I cannot seem to figure out what I'm trying to do. I have an array with many percent values placed inside and I'm printing out the first 5 of them. The $percent variables are acquired through similar_text
$array=array($percent12, $percent13, $percent14,
$percent15, $percent16, $percent17,
$percent18, $percent19, $percent110,
$percent111, $percent112, $percent113,
$percent114, $percent115, $percent116,
$percent117, $percent118, $percent119,
$percent120);
print_r(array_slice($array,0,5));
and it outputs like this:
Array ( [0] => 36.015505697169 [1] => 2.4181626187962 [2] => 2.4181626187962 [3] => 5.2153134902083 [4] => 100 )
So what i'm trying to figure out here is if it's possible to print the results of my array as they are listed above. example output would look like this:
Array ( [percent12] => 36.015505697169 [percent13] => 2.4181626187962 [percent14] => 2.4181626187962 [percent15] => 5.2153134902083 [percent16] => 100 )
i feel like this isn't possible, but if not, is there a way to assign the
[0]=> 36.015505697169 [1]=> 2.4181626187962
...etc to output something else say like:
[web0]=> 36.015505697169 [web1] => 2.4181626187962
Please help!! It's driving me crazy!!
You need to make it an associative array:
$array=array('percent12' => $percent12,
'percent13' => $percent13,
...);
I recommend using array_combine()
Basically you're just going to setup your new array with the keys, and pass in your current array for the values, thus creating a new array with the keys you want in the right place.
Try like
$myArr = array_slice($array,0,5);
$i = 0;
foreach($myArr as $key => $value) {
$newArr['web'.$i++] = $value;
}
print_r($newArr);
I want to get all the array data where keys has the characters 'ch' from the start. How do I get it?
Array ( [editpostid] => 0 [editpostcat] => 1 [ch114] => on [ch115] => on )
The keys of the data may vary as the numbers come from the record id's from the database.
how do I place all the data with 'ch' in the start of keys on to a separate array?
Do like this
<?php
$arr = array('ch'=>10,'abch'=>20,'ch23'=>45);
$newarr=array();
foreach($arr as $k=>$v)
{
if(substr(strtolower($k),0,2)=='ch')
{
array_push($newarr,$v); // Make use of this if you just need the values
//$newarr[$k]=$v; // Uncomment this and comment above statement, if you need the keys too
}
}
print_r($newarr);
OUTPUT:
Array
(
[0] => 10
[1] => 45
)
$charray=array();
foreach($yourarray as $key=>$value){
if(preg_match("/^ch/",$key)){
$charray[$key]=>$value;
}
}
//$charray is the new arrayas you asked for
echo implode(',',$charray);
refer official documentation for preg_match for more information