I have an array, so I wanted to add keys to each value, for example, if an array contains Facebook URL then the key should be Facebook if an array has a link of Instagram then the key should be Instagram and the list goes on.
Here's the code
<?php
foreach($social_media as $social){
$typesocial = $social['type'];
if($social['type'] === 'social network') {
$val[] = $social['url']['resource'];
}
}
print_r($val);
?>
Array (
[0] => https://plus.google.com/+beyonce
[1] => https://twitter.com/Beyonce
[2] => https://www.facebook.com/beyonce
[3] => https://www.instagram.com/beyonce/
[4] => http://www.weibo.com/beyonceofficial
)
It should become, if the value has a link of twitter then the key should be twitter if Instagram then it should be Instagram
Array (
[google] => https://plus.google.com/+beyonce
[twitter] => https://twitter.com/Beyonce
[facebook] => https://www.facebook.com/beyonce
[instagram] => https://www.instagram.com/beyonce/
[weibo] => http://www.weibo.com/beyonceofficial
)
$indexed = [
'https://plus.google.com/+beyonce',
'https://twitter.com/Beyonce',
'https://www.facebook.com/beyonce',
'https://www.instagram.com/beyonce/',
'http://www.weibo.com/beyonceofficial',
];
Assuming the host consists of 2 or 3 parts
$assoc = [];
foreach($indexed as $url) {
$host = explode('.', parse_url($url, PHP_URL_HOST));
switch (count($host)) {
case 2:
$assoc[$host[0]] = $url;
break;
case 3:
$assoc[$host[1]] = $url;
}
}
Will output $assoc as
array(5) {
'google' => string(32) "https://plus.google.com/+beyonce"
'twitter' => string(27) "https://twitter.com/Beyonce"
'facebook' => string(32) "https://www.facebook.com/beyonce"
'instagram' => string(34) "https://www.instagram.com/beyonce/"
'weibo' => string(36) "http://www.weibo.com/beyonceofficial"
}
This maybe? Hope to help
EDITED
$array = Array (
0 => 'https://plus.google.com/+beyonce',
1 => 'https://twitter.com/Beyonce',
2 => 'https://www.facebook.com/beyonce',
3 => 'https://www.instagram.com/beyonce/',
4 => 'http://www.weibo.com/beyonceofficial',
6 => 'http://www.bbc.co.uk/a/witty/documentary'
);
$output = Array();
foreach($array as $key => $url){
$urlarr = parse_url($url);
$arr = explode('.',$urlarr['host']);
$name = $arr[count($arr) - 2];
if($name == 'co'){
$name = $arr[count($arr) - 3];
}
$output[$name] = $url;
}
print_r($output);
You may want to use strpos() so you can find the words and add specific key, something like this:
$new_array = [];
foreach($old_array AS $value){
if(strpos($value, 'facebook')) {
$new_array['facebook'] = $value;
}elseif(strpos($value, 'instagram')) {
$new_array['instagram'] = $value;
}elseif(strpos($value, 'twitter')) {
$new_array['twitter'] = $value;
}else{ //so it goes...
$new_array['unknow'] = $value;
}
}
Of course if you have two url with facebook, the second will overwrite the first one so depends of what you need you may add an aditional index... like:
$new_array['facebook'][] = $value;
Hope it helps!
An quick/easy-ish way to approach this might be to do a regex match on the domains.
For example, if you have a finite set of social media and can trust the middle of the domain name, then you can extract that part of the url to put it as part of your key.
For example the regex /google|twitter/ would match google from https://plus.google.com/+beyonce. This can then be used for your key.
So looping through your set, you'd run preg_match which would attempt to find the key based on the domain name. preg_match has a parameter called $match that then stores the google part of what you're matching. You can use this to be the key of your formatted array.
$array = [
'https://plus.google.com/+beyonce',
'https://twitter.com/Beyonce',
'https://www.facebook.com/beyonce',
'https://www.instagram.com/beyonce/',
'http://badmedia.com/beyonce',
'http://www.weibo.com/beyonceofficial'
];
$keyed = [];
foreach ($array as $i => $url) {
preg_match('/google|twitter|facebook|instagram|weibo/', $url, $match);
$key = isset($match[0]) ? $match[0] : 'notfound-' . $i;
$keyed[$key] = $url;
}
The result here is that $keyed now contains your array for $keyed['google'] and the others.
Add or remove from the google|twitter|facebook|instagram|weibo to have a |another where you want to have more or less support for different sites.
It's not very scalable, and if the domain doesn't match a key you want to use, then in this case I've set it to create a key called notfound- with the original array key. (I've added badmedia.com to the list to demonstrate it.). You also run the risk of having a conflict where someone might be smart and have their Facebook username as "nottwitter" which will technically match "twitter"
So what you might want to consider rather than relying on the domain to provide your key for you, to keep a regex match for each full domain name. You could store these regex queries against the key you wanted to use, and nest your two loops to find a match...
For example:
$socialMedia = [
'facebook' => '/^(https?:\/\/)?(www\.)?facebook.com\/[a-zA-Z0-9(\.\?)?]/',
]
foreach ($array as $url) {
foreach ($socialMedia as $key => $regex) {
if (preg_match($regex, $url)) {
$keyed[$key] = $url;
}
}
}
(Shoutout to https://gist.github.com/atomicpages/4619196 for the full FB domain regex)
For very small sets (which I imagine you're dealing with at any one time) this would scale slightly better and give you a better result... It also rejects and removes any you don't support, but you would need to catch those separately.
For larger sets you probably want to look at how you collect the urls in the first place... Rather than accept any list, maybe have the form or API call you're receiving these from state which one it is on the way in.
Related
I am trying to group some foreach results based on the first 3 sets of characters.
For example i am currently listing sku codes for products and they look like this:
REF-MUSBOM-0500-ORA
REF-PROCOF-0001-LAT
REF-WHEREF-0001-TRO
REF-WHEREF-0001-ORA
REF-SHAKER-0700-C/B
REF-CREMON-0100-N/A
REF-GLUSUL-0090-N/A
REF-CRECAP-0090-N/A
REF-ALBFER-0120-N/A
REF-TSHCOT-LARG-BLK
REF-TSHCOT-MEDI-BLK
REF-ALBMAG-0090-N/A
REF-GYMJUG-2200-N/A
REF-OMEGA3-0090-N/A
REF-NEXGEN-0060-N/A
REF-VITAD3-0100-N/A
REF-SSSHAK-0739-N/A
REF-GINKGO-0090-N/A
REF-DIGEZY-0090-N/A
REF-VEST00-MEDI-N/A
REF-VEST00-LARG-N/A
REF-CREMON-0250-N/A
REF-MSM----0250-N/A
REF-GRNTEA-0100-N/A
REF-COLOST-0100-N/A
REF-GLUCHO-0090-N/A
REF-ZINCMA-0100-N/A
REF-BETALA-0250-N/A
REF-DRIBOS-0250-N/A
REF-HMB000-0090-N/A
REF-ALACID-0090-N/A
REF-CLA000-0090-N/A
REF-ACETYL-0090-N/A
REF-NXGPRO-0090-N/A
REF-LGLUTA-0250-N/A
REF-BCAA20-0200-N/A
REF-FLAPJA-0012-ACR
REF-FLAPJA-0012-MAP
REF-LCARNI-0100-N/A
REF-CORDYC-0090-N/A
REF-CREMON-0500-N/A
REF-BCAAEN-0330-APP
REF-PREWKT-0300-FPU
REF-TESFUS-0090-N/A
REF-AMIIFUS-0300-GAP
REF-AMIIFUS-0300-WME
REF-BCAINT-0400-FPU
REF-KRILLO-0090-N/A
REF-AMIIFUS-0300-PLE
REF-AMIIFUS-0300-FPU
REF-BCAINT-0400-WME
REF-ENZQ10-0090-N/A
REF-THERMO-0100-N/A
REF-LGLUTA-0500-N/A
REF-RBAR00-0012-DCB
REF-RBAR00-0012-PBC
REF-RBAR00-0012-WCR
REF-IMHEAV-2200-CHO
REF-PROCOF-0012-N/A
REF-DIEPRO-0900-STR
REF-DIEPRO-0900-BOF
REF-DIEPRO-0900-CHO
REF-INWPRO-0900-VAN
REF-INWPRO-0900-BOF
REF-INWPRO-0900-BCS
REF-INWPRO-0900-CHO
REF-INWPRO-0900-CMI
REF-INWPRO-0900-RAS
REF-INWPRO-0900-STR
REF-INWPRO-0900-CIN
REF-INWPRO-0900-CPB
REF-EGGPRO-0900-CHO
REF-EGGPRO-0900-VAN
REF-MICCAS-0909-CHO
REF-MICCAS-0909-CMI
REF-MICCAS-0909-VAN
REF-MICCAS-0909-STR
REF-BCAA50-0500-N/A
REF-MICWHE-0909-STR
REF-MICWHE-0909-VAN
REF-MICWHE-0909-CHIO
REF-MICWHE-0909-BAN
REF-1STOXT-2030-STR
REF-1STOXT-2030-VAN
REF-1STOXT-2030-CHO
REF-MUSBOM-0600-BCH
REF-MUSBOM-0600-FPU
REF-MUSBCF-0600-BCH
REF-MUSBCF-0600-FPU
REF-VEGANP-2100-STR
REF-VEGANP-2100-CHO
REF-INMPRO-2270-CPB
REF-DIETMR-2400-CPB
REF-INMPRO-2270-SCR
REF-INMPRO-2270-VIC
REF-MATRIX-1800-FRU
REF-INMPRO-2270-BOF
REF-MATRIX-1800-CHO
REF-INMPRO-2270-CHO
REF-ONESTO-2100-CHO
In the above list there are 2 skus which are:
REF-WHEREF-0001-TRO
REF-WHEREF-0001-ORA
The first 3 sets of characters split by - are the same. What would be the best approach of grouping all results leaving me an array something like this:
Array
(
[REF-WHEREF-0001] => Array
(
[0] => REF-WHEREF-0001-TRO
[1] => REF-WHEREF-0001-ORA
)
)
Are the first 3 groups (excluding the multiple -) always 13 characters? Then do something like this:
<?php
$arr = ["REF-MUSBOM-0500-ORA",
"REF-PROCOF-0001-LAT",
"REF-WHEREF-0001-TRO",
"REF-WHEREF-0001-PPL"];
$resultArr = [];
foreach ($arr as $sku) {
$resultArr[substr($sku, 0, 15)][] = $sku;
}
var_dump($resultArr);
If that length varies you might want to work with a regex or the strpos() of the third -.
I must say that I think you could come up with this yourself, since you were already thinking in the right direction i.e. foreach()
EDIT: Because I found other solutions more elegant looking, I decided to compare efficiency. This solution is a lot faster than the other ones.
I always create a new array with the index that I need for group, try this:
$arr=array('REF-MUSBOM-0500-ORA',
'REF-PROCOF-0001-LAT',
'REF-WHEREF-0001-TRO');
$newarr=array();
foreach($arr as $a){
$b=explode('-',$a);
array_pop($b);
$b=implode("-", $b);
$newarr[$b][]=$a;
}
echo '<pre>',print_r($newarr),'</pre>';
You will need to pick a group with some basics use of explode, implode and str_replace.
What does this solution do.
loop through the array of your items
explode to get last item index of exploded string assuming that it
would be dynamic in the end
implode & str_replace again to find out string of group name
And last strpos & in_array to have sample reponse
Solution
$array = array(
'REF-MUSBOM-0500-ORA',
'REF-PROCOF-0001-LAT',
'REF-WHEREF-0001-TRO',
'REF-WHEREF-0001-ORA',
'REF-SHAKER-0700-C/B',
'REF-CREMON-0100-N/A',
'REF-GLUSUL-0090-N/A',
'REF-CRECAP-0090-N/A',
'REF-ALBFER-0120-N/A',
);
$new_array = array();
foreach ($array as $key => $val) {
$group_arr = explode('-', $val);
$end = end($group_arr);
$combined_group = implode('-', $group_arr);
$group = str_replace('-' . $end, '', $combined_group);
if (strpos($val, $group) !== false && !in_array($group, $new_array)) {
$new_array[$group][] = $val;
}
}
echo '<pre>';print_r($new_array);echo '</pre>';
See demo on Sandbox
I have a pretty large array that I would need to parse, but the request changes depending on enabled/disabled parameters.
For example:
$array['a'][1]['b'][1]['c'][1] = 'asd';
$str = $array['a'][1];
dd($str);
This would give me:
Array
(
[b] => Array
(
[1] => Array
(
[c] => Array
(
[1] => asd
)
)
)
)
Which, of course, is correct. But now, if I know, that I need also the next parameter, I would need to add that like $str = $array['a'][1]['b'];.
But since there are way too many combinations, I wondered, if I can construct the call manually, something like this":
$str = $array['a'][1];
if ($b) {
$str .= ['b'][1];
}
if ($c) {
$str .= ['c'][1];
}
dd($str);
Any hints will be appreciated.
PS: I know I can do this with eval, but was really looking for a better solution:
eval("\$str = \$array$str;");
dd($str);
It can be done with Reference
$string = "['a'][1]['b'][1]";
// Maybe, not optimal, but it's not the point of the code
preg_match_all('/\[\'?([^\]\']+)\'?\]/', $string, $steps);
// "Root" of the array
$p = &$array;
foreach($steps[1] as $s) {
// Next step with current key
if (isset($p[$s]) && is_array($p)) $p = &$p[$s];
else throw new Exception("No such item");
}
// Target value
$str = $p;
demo
I'm working on a search-based website, and am trying to pass parameters using SEO-friendly URLs.
Is it possible to pass the following URL and get the URL in CodeIgniter?
http://www.example.com/search/prize/10/13/14.5/size/xl/2xl/color/black/white-grey/
I am able to create the URL, but I want to get the URL values like $prize = array("10","13","14.5"), $size= array("xl","2xl"), and $color = array("black","white-grey").
I tried to use the uri_to_assoc() function, but it didn't work. I get the following output:
[price] => 10,
[13] => 14.5
...
which is wrong.
Note: I tried to use $this->uri->segment(1), etc., but in this case, the segment position is dynamic.
For example, users may search for only prices of $10, so the URL will get changed to:
http://www.example.com/search/prize/10/size/xl/2xl/color/black/white-grey/
Now the segment position of getting the size must be changed. In this case, I want:
$prize = array("10");
$size = array("xl", "2xl");
$color = array("black", "white-grey");
How can I achieve this?
You are using quite the unconventional "friendly URI" format. Normally when passing parameters there is a single identifier and then the parameter e.g. /name/key/name/key/name/key.
When you use the correct format /name/key/name/key/name/key in conjunction with uri_to_assoc(), you would get:
array(
'name' => 'key',
// etc...
)
but using something like /prize/1/2/3/size/s/m/l/color/black/white/grey would yield:
array(
'prize' => 1,
2 => 3,
'size' => 's',
'm' => 'l',
// etc...
)
Which is useless to you.
You will have to fetch all of the segments individually and build your arrays with a foreach:
$segments = $this->uri->segment_array();
$prize = array();
$size = array();
$color = array();
$curKey = '';
foreach ($segments as $seg) {
if (in_array($seg, array('prize', 'size', 'color'))) {
$curKey = $seg; continue;
}
if (!empty($curKey)) ${$curKey}[] = $seg;
}
// use $prize, $size, and $color as you wish
or alternatively using a multi-dimensional array:
$parameters = array(
'prize' => array(),
'size' => array(),
'color' => array(),
);
$segments = $this->uri->segment_array();
$curKey = '';
foreach ($segments as $seg) {
if (in_array($seg, array('prize', 'size', 'color'))) {
$curKey = $seg; continue;
}
if (!empty($curKey)) $parameters[$curKey][] = $seg;
}
Fetch all the segments
Iterate over them, check each for keywords like size, color, etc. (make a whitelist)
If a keyword is found, assume the segment values until the next keyword segment or the end are the values for that specific keyword (so xl and 2xl will denote the size if preceeded with a keyword size, etc.)
So here's the input:
$in['a--b--c--d'] = 'value';
And the desired output:
$out['a']['b']['c']['d'] = 'value';
Any ideas? I've tried the following code without any luck...
$in['a--b--c--d'] = 'value';
// $str = "a']['b']['c']['d";
$str = implode("']['", explode('--', key($in)));
${"out['$str']"} = 'value';
This seems like a prime candidate for recursion.
The basic approach goes something like:
create an array of keys
create an array for each key
when there are no more keys, return the value (instead of an array)
The recursion below does precisely this, during each call a new array is created, the first key in the list is assigned as the key for a new value. During the next step, if there are keys left, the procedure repeats, but when no keys are left, we simply return the value.
$keys = explode('--', key($in));
function arr_to_keys($keys, $val){
if(count($keys) == 0){
return $val;
}
return array($keys[0] => arr_to_keys(array_slice($keys,1), $val));
}
$out = arr_to_keys($keys, $in[key($in)]);
For your example the code above would evaluate as something equivalent to this (but will work for the general case of any number of -- separated items):
$out = array($keys[0] => array($keys[1] => array($keys[2] => array($keys[3] => 'value'))));
Or in more definitive terms it constructs the following:
$out = array('a' => array('b' => array('c' => array('d' => 'value'))));
Which allows you to access each sub-array through the indexes you wanted.
$temp = &$out = array();
$keys = explode('--', 'a--b--c--d');
foreach ($keys as $key) {
$temp[$key] = array();
$temp = &$temp[$key];
}
$temp = 'value';
echo $out['a']['b']['c']['d']; // this will print 'value'
In the code above I create an array for each key and use $temp to reference the last created array. When I run out of keys, I replace the last array with the actual value.
Note that $temp is a REFERENCE to the last created, most nested array.
Let's assume I know that there is key "twoVal", but I do not know what is after it. How do I get to the next key for that matter? Shoud I know the position of key "twoVal"? Or there is another way around?
$arr = array('Cool Viski' => array('oneVal' => '169304',
'twoVal' => '166678',
'threeVal' => '45134'));
$keys = array_keys($arr['Cool Viski']);
$position = array_search('twoVal', $keys);
if (isset($keys[$position + 1])) {
$keyAfterTwoVal = $keys[$position + 1];
}
$arr = array('Cool Viski' => array('oneVal' => '169304',
'twoVal' => '166678',
'threeVal' => '45134'));
foreach($arr as $s=>$v){
foreach($v as $val){
if(key($v) == "twoVal"){
$t=next($v);
print "next key: ".key($v)."\n";
print "next key value is: ".$t."\n";;
}else{
next($v);
}
}
}
You might be interested in the various array seeking functions, but unless a PHP array is indexed only by integers there's no guarantee of order on the keys.