How can I change array items? - php

I have an array containing links. I am trying to cut a part of those links. For example:
$array = [
"https://eksisozluk.com/merve-sanayin-pizzaciya-kapiyi-ciplak-acmasi--5868043?a=popular",
"https://eksisozluk.com/merve-sanayin-pizzaciya-kapiyi-ciplak-acmasi--5868043?a=popular"
];
I want change these links like below:
array(2) {
[0]=>
string(91) "https://eksisozluk.com/merve-sanayin"
[1]=>
string(91) "https://eksisozluk.com/merve-sanayin"
[2]=>
}
Is there any possible way to edit array items?

Given the array:
$array = [
"https://eksisozluk.com/merve-sanayin-pizzaciya-kapiyi-ciplak-acmasi--5868043?a=popular",
"https://eksisozluk.com/merve-sanayin-pizzaciya-kapiyi-ciplak-acmasi--5868043?a=popular"
];
Using array_walk() (modifies the array in place).
Using a regular expression this time:
function filter_url(&$item)
{
preg_match('|(https:\/\/\w+\.\w{2,4}\/\w+-\w+)-.+|', $item, $matches);
$item = $matches[1];
}
array_walk($array, 'filter_url');
(See it working here).
Note that filter_url passes the first parameter by reference, as explained in the documentation, so changes to each of the array items are performed in place and affect the original array.
Using array_map() (returns a modified array)
Simply using substr, since we know next to nothing about your actual requirements:
function clean_url($item)
{
return substr($item, 0, 36);
}
$new_array = array_map('clean_url', $array);
Working here.
The specifics of how actually filter the array elements are up to you.
The example shown here seems kinda pointless, since you are setting all elements exactly to the same value. If you know the lenght you can use substr, or you could just could write a more robust regex.
Since all the elements of your input array are the same in the example, I am going to assume this doesn't represent your actual input.
You could also iterate the array using either for, foreach or while, but either of those options seems less elegant when you have specific array functions to deal with this kind of situation.

There are multiple ways. One way is to iterate over the items and clip them with substr().
$arr = array("https://eksisozluk.com/merve-sanayin-pizzaciya-kapiyi-ciplak-acmasi--5868043?a=popular",
"https://eksisozluk.com/merve-sanayin-pizzaciya-kapiyi-ciplak-acmasi--5868043?a=popular");
for ($i = 0; $i < count($arr); $i++)
{
$arr[$i] = substr($arr[$i], 0, 36);
}

Related

I want to make custom array shuffle in php with respect to integer

Looking the function below:
function CustomShuffle($arr, $para){
............................
............................
return $array;
}
Suppose this is an array:
$array = array("red","green","blue","yellow","purple");
looking output something like below (May be different ordered but must be same for same integer parameter)
$result = CustomShuffle($array, 10);
// output: array("blue","purple","yellow","red","green") same
$result = CustomShuffle($array, 12);
// output: array("purple","yellow","red","green","blue")
$result = CustomShuffle($array, 10);
// output: array("blue","purple","yellow","red","green") same
$result = CustomShuffle($array, 7);
// output: array("blue","yellow","purple","red","green")
Simply, array will be shuffled with respect to integer parameter but output will be same for same parameter. Is it possible?
Yes this is possible, how it happens does come down to a desired implementation and how many permutations you wish to allow. A very naive method of accomplishing this is to have a loop that runs $para times within CustomShuffle that would array_shift() an element then array_push() that same element. This method would only give you count($array) possible outcomes, meaning numbers congruent modulo count($array) would produce the same result.
The optimal algorithm would allow you to take advantage of the maximum combinations, which would be gmp_fact(count($array)), or simply the factorial of the length of the input array. There is no possible way to achieve more unique combinations than this value, so no matter what algorithm you design, you will always have a constraint on the value of $para until you eventually encounter a combination already seen.

Add or modify part of an array as a mysql string

I currently have a column in mysql database that stores a string with delimiters so I can convert it into an array in php.
An example string looks like this:
23,1,1|72,2,0|16,3,1|...etc.
It essentially divides it into 3 major groups with |, and 3 smaller ones with , (if there's a cleaner way, let me know):
1st number is an ID number for an article from a different table
2nd is just a number for indenting purposes
3rd is for visible or not (0 or 1).
I will have an admin section where we'll be able to re-order the major groups (i.e., move group 3 to position 2) and modify specific numbers from the sub-groups (e.g. change 72,1,0 to 72,2,0) I'm not sure how I can accomplish this.
How do I loop through these modifications while keeping the order (or new order) when reinserting into the database?
I was thinking of adding a another number to my string that would determine the position of each major group? Something like this:
1[23,1,1]2[72,2,0]3[16,3,1]
But how do I loop through this and move things around?
Any help would be greatly appreciated.
I agree with the comments about normalization, but if you insist on doing it this way, or are stuck with an existing schema you cannot alter, use the PHP serialize/unserialize functions if you can, rather than string parsing. This will at least allow you to retrieve the data into PHP and modify the array and then save it back.
http://php.net/manual/en/function.serialize.php
I'm joining all comments about the approach used to store data, but nevertheless.
This what can help you to move forward:
/** #var string $s Assumed packet */
$s = "23,3,1|72,1,0|16,2,1"; // Indent is not ordered
/** #var array $parsed Parsed packet */
$parsed = array_map(function ($segment) {
list($artId, $indent, $visibility) = explode(',', $segment);
return [
'ArticleId' => (int)$artId,
'Indent' => (int)$indent,
'Visible' => (int)$visibility !== 0
];
}, explode('|', $s));
usort($parsed, function (array $a, array $b) {
return ($a['Indent'] < $b['Indent']) ? -1 : 1;
});
You'll get following $parsed structure sorted by Indent key:
array(3) {
[0] => array(3) {
["ArticleId"]=> int(23)
["Indent"]=> int(1)
["Visible"]=> bool(true)
}
[1] => array(3) {
["ArticleId"]=> int(72)
["Indent"]=> int(2)
["Visible"]=> bool(false)
}
[2] => array(3) {
["ArticleId"]=> int(16)
["Indent"]=> int(3)
["Visible"]=> bool(true)
}
}
Thus you can alter Indent as you want just applying usort() before/after parsing.
Regarding storing this structure in database the way you decided, you can use JSON format (json_encode(),json_decode()). Such "serialization" way faster than proposed serialize() method and way more faster than $parsed approach + more readable. If you worry about redundancy you can json_encode() array without array keys and add them on parsing or use directly [0], [1], [2] knowing the correspondence beforehand.
If you use json_*() functions you can omit structure parsing bec. it will be decoded right the same you've encoded it for saving. Order can be defined on save using same usort(). This can be considered as improvement by reducing excessive sorts bec. readings/decodings will occur more frequently than saves.
I was interested with your question. So i create this. It may not like what you desired.
<?php
$string = "23,1,1|72,2,0|16,3,1|";
$explode = explode("|", $string);
$a = array();
for($x = 0;$x<count($explode)-1;$x++)
{
$a[] = $explode[$x];
$b[] =explode(',',substr($explode[$x], strpos($explode[$x], ",") + 1));
}
for($y=0;$y<count($b);$y++){
echo $b[$y][0]. '=>'. $a[$y] . '<br>';
}
?>

PHP - How to test a multidimensional array for duplicate element values in any order

I'm not sure the title really gets across what I'm asking, so here's what I'm trying to do:
I have an array of arrays with four integer elements each, ie.
Array(Array(1,2,3,4), Array(4,2,3,1), Array(18,3,22,9), Array(23, 12, 33, 55))
I basically need to remove one of the two arrays that have the same values in any order, like indices 0 and 1 in the example above.
I can do this pretty easily when there are only two elements to check, using the best answer code in this question.
My multidimensional array can have 1-10 arrays at any given time, so I can't seem to figure out the best way to process a structure like that and remove arrays that have the same numbers in any order.
Thanks so much!
I've been thinking about this, and I think using a well designed closure with array_filter might be the way I'd go about this:
$matches = array();
$array = array_filter($array, function($ar) use (&$matches) {
sort($ar);
if(in_array($ar, $matches)) {
return false;
}
$matches[] = $ar;
return true;
});
See here for an example: http://ideone.com/Zl7tlR
Edit: $array will be your final result, ignore $matches as it's just used during the filter closure.

How to change order of substrings inside a larger string?

This is fairly confusing, but I'll try to explain as best I can...
I've got a MYSQL table full of strings like this:
{3}12{2}3{5}52
{3}7{2}44
{3}15{2}2{4}132{5}52{6}22
{3}15{2}3{4}168{5}52
Each string is a combination of product options and option values. The numbers inside the { } are the option, for example {3} = Color. The number immediately following each { } number is that option's value, for example 12 = Blue. I've already got the PHP code that knows how to parse these strings and deliver the information correctly, with one exception: For reasons that are probably too convoluted to get into here, the order of the options needs to be 3,4,2,5,6. (To try to modify the rest of the system to accept the current order would be too monumental a task.) It's fine if a particular combination doesn't have all five options, for instance "{3}7{2}44" delivers the expected result. The problem is just with combinations that include option 2 AND option 4-- their order needs to be switched so that any combination that includes both options 2 and 4, the {4} and its corresponding value comes before the {2} and it's corresponding value.
I've tried bringing the column into Excel and using Text to Columns, splitting them up by the "{" and "}" characters and re-ordering the columns, but since not every string yields the same number of columns, the order gets messed up in other ways (like option 5 coming before option 2).
I've also experimented with using PHP to explode each string into an array (which I thought I could then re-sort) using "}" as the delimiter, but I had no luck with that either because then the numbers blend together in other ways that make them unusable.
TL;DR: I have a bunch of strings like the ones quoted above. In every string that contains both a "{2}" and a "{4}", the placement of both of those values needs to be switched, so that the {4} and the number that follows it comes before the {2} and the number that follows it. In other words:
{3}15{2}3{4}168{5}52
needs to become
{3}15{4}168{2}3{5}52
The closest I've been able to come to a solution, in pseudocode, would be something like:
for each string,
if "{4}" is present in this string AND "{2}" is present in this string,
take the "{4}" and every digit that follows it UNTIL you hit another "{" and store that substring as a variable, then remove it from the string.
then, insert that substring back into the string, at a position starting immediately before the "{2}".
I hope that makes some kind of sense...
Is there any way with PHP, Excel, Notepad++, regular expressions, etc., that I can do this? Any help would be insanely appreciated.
EDITED TO ADD: After several people posted solutions, which I tried, I realized that it would be crucial to mention that my host is running PHP 5.2.17, which doesn't seem to allow for usort with custom sorting. If I could upvote everyone's solution (all of which I tried in PHP Sandbox and all of which worked), I would, but my rep is too low.
How would something like this work for you. The first 9 lines just transform your string into an array with each element being an array of the option number and value. The Order establishes an order for the items to appear in and the last does a usort utilizing the order array for positions.
$str = "{3}15{2}2{4}132{5}52{6}22";
$matches = array();
preg_match_all('/\{([0-9]+)\}([0-9]+)/', $str, $matches);
array_shift($matches);
$options = array();
for($x = 0; $x < count($matches[0]); $x++){
$options[] = array($matches[0][$x], $matches[1][$x]);
}
$order = [3,4,2,5,6];
usort($options, function($a, $b) use ($order) {
return array_search($a[0], $order) - array_search($b[0], $order);
});
To get you data back into the required format you would just
$str = "";
foreach($options as $opt){
$str.="{".$opt[0]."}".$opt[1];
}
On of the bonuses here is that when you add a new options type inserting adjusting the order is just a matter of inserting the option number in the correct position of the $order array.
First of all, those options should probably be in a separate table. You're breaking all kinds of normalization rules stuffing those things into a string like that.
But if you really want to parse that out in php, split the string into a key=>value array with something like this:
$options = [];
$pairs = explode('{', $option_string);
foreach($pairs as $pair) {
list($key,$value) = explode('}', $pair);
$options[$key] = $value;
}
I think this will give you:
$options[3]=15;
$options[2]=3;
$options[4]=168;
$options[5]=52;
Another option would be to use some sort of existing serialization (either serialize() or json_encode() in php) instead of rolling your own:
$options_string = json_encode($options);
// store $options_string in db
then
// get $options_string from db
$options = json_decode($options_string);
Here's a neat solution:
$order = array(3, 4, 2, 5, 6);
$string = '{3}15{2}3{4}168{5}52';
$split = preg_split('#\b(?={)#', $string);
usort($split, function($a, $b) use ($order) {
$a = array_search(preg_replace('#^{(\d+)}\d+$#', '$1', $a), $order);
$b = array_search(preg_replace('#^{(\d+)}\d+$#', '$1', $b), $order);
return $a - $b;
});
$split = implode('', $split);
var_dump($split);

Determine whether an array is associative (hash) or not [duplicate]

This question already has answers here:
How to check if PHP array is associative or sequential?
(60 answers)
Closed last year.
I'd like to be able to pass an array to a function and have the function behave differently depending on whether it's a "list" style array or a "hash" style array. E.g.:
myfunc(array("One", "Two", "Three")); // works
myfunc(array(1=>"One", 2=>"Two", 3=>"Three")); also works, but understands it's a hash
Might output something like:
One, Two, Three
1=One, 2=Two, 3=Three
ie: the function does something differently when it "detects" it's being passed a hash rather than an array. Can you tell I'm coming from a Perl background where %hashes are different references from #arrays?
I believe my example is significant because we can't just test to see whether the key is numeric, because you could very well be using numeric keys in your hash.
I'm specifically looking to avoid having to use the messier construct of myfunc(array(array(1=>"One"), array(2=>"Two"), array(3=>"Three")))
Pulled right out of the kohana framework.
public static function is_assoc(array $array)
{
// Keys of the array
$keys = array_keys($array);
// If the array keys of the keys match the keys, then the array must
// not be associative (e.g. the keys array looked like {0:0, 1:1...}).
return array_keys($keys) !== $keys;
}
This benchmark gives 3 methods.
Here's a summary, sorted from fastest to slowest. For more informations, read the complete benchmark here.
1. Using array_values()
function($array) {
return (array_values($array) !== $array);
}
2. Using array_keys()
function($array){
$array = array_keys($array); return ($array !== array_keys($array));
}
3. Using array_filter()
function($array){
return count(array_filter(array_keys($array), 'is_string')) > 0;
}
PHP treats all arrays as hashes, technically, so there is not an exact way to do this. Your best bet would be the following I believe:
if (array_keys($array) === range(0, count($array) - 1)) {
//it is a hash
}
No, PHP does not differentiate arrays where the keys are numeric strings from the arrays where the keys are integers in cases like the following:
$a = array("0"=>'a', "1"=>'b', "2"=>'c');
$b = array(0=>'a', 1=>'b', 2=>'c');
var_dump(array_keys($a), array_keys($b));
It outputs:
array(3) {
[0]=> int(0) [1]=> int(1) [2]=> int(2)
}
array(3) {
[0]=> int(0) [1]=> int(1) [2]=> int(2)
}
(above formatted for readability)
My solution is to get keys of an array like below and check that if the key is not integer:
private function is_hash($array) {
foreach($array as $key => $value) {
return ! is_int($key);
}
return false;
}
It is wrong to get array_keys of a hash array like below:
array_keys(array(
"abc" => "gfb",
"bdc" => "dbc"
)
);
will output:
array(
0 => "abc",
1 => "bdc"
)
So, it is not a good idea to compare it with a range of numbers as mentioned in top rated answer. It will always say that it is a hash array if you try to compare keys with a range.
Being a little frustrated, trying to write a function to address all combinations, an idea clicked in my mind: parse json_encode result.
When a json string contains a curly brace, then it must contain an object!
Of course, after reading the solutions here, mine is a bit funny...
Anyway, I want to share it with the community, just to present an attempt to solve the problem from another prospective (more "visual").
function isAssociative(array $arr): bool
{
// consider empty, and [0, 1, 2, ...] sequential
if(empty($arr) || array_is_list($arr)) {
return false;
}
// first scenario:
// [ 1 => [*any*] ]
// [ 'a' => [*any*] ]
foreach ($arr as $key => $value) {
if(is_array($value)) {
return true;
}
}
// second scenario: read the json string
$jsonNest = json_encode($arr, JSON_THROW_ON_ERROR);
return str_contains($jsonNest, '{'); // {} assoc, [] sequential
}
NOTES
php#8.1 is required, check out the gist on github containing the unit test of this method + Polyfills (php>=7.3).
I've tested also Hussard's posted solutions, A & B are passing all tests, C fails to recognize: {"1":0,"2":1}.
BENCHMARKS
Here json parsing is ~200 ms behind B, but still 1.7 seconds faster than solution C!
What do you think about this version? Improvements are welcome!

Categories