php url 唯一数组

php array unique for urls

我需要从数组中识别 unique urls

以下所有变体都应算作相等:

http://google.com
https://google.com
http://www.google.com
https://www.google.com
www.google.com
google.com

我有以下解决方案:

public static function array_unique_url(array $array) : array
{
    $uniqueArray = [];
    foreach($array as $item) {
        if(!self::in_array_url($item, $uniqueArray)){
            $uniqueArray[] = $item;
        }
    }
    return $uniqueArray;
}

public static function in_array_url(string $needle, array $haystack): bool {
    $haystack = array_map([self::class, 'normalizeUrl'], $haystack);
    $needle = self::normalizeUrl($needle);

    return in_array($needle, $haystack);
}

public static function normalizeUrl(string $url) {
    $url = strtolower($url);
    return preg_replace('#^(https?://)?(www.)?#', '', $url);
}

然而,这不是很有效的 O(n^2)。谁能指出我更好的解决方案?

in_array 很贵。与其这样做,不如创建一个散列并将值存储为它们的计数。 类似于:

$myHash = []; //a global array to hold values.

检查时,请执行以下操作:

if(!empty($myHash[$needle] )){
   //already exits
}

我还没有测试过,但也许像这样的东西会起作用:

function getUniqueUrls(array $urls)
{
    $unique_urls = [];
    foreach ($urls as $url) {
        $normalized_url = preg_replace('#^(https?://)?(www.)?#', '', strtolower($url));
        $unique_urls[$normalized_url] = true;
    }

    return array_keys($unique_urls);
}

$arr = [
    'http://google.com',
    'https://google.com',
    'http://www.google.com',
    'https://www.google.com',
    'www.google.com',
    'google.com'
];

$unique_urls = getUniqueUrls($arr);

这是一个简化版本。它不使用 preg_replace 因为它花费很多。也不会做任何不必要的字符串操作。

$urls = array(
    "http://google.com",
    "https://google.com",
    "http://www.google.com",
    "https://www.google.com",
    "www.google.com",
    "google.com"
);

$uniqueUrls = array();

foreach($urls as $url) {
    $subPos = 0;
    if(($pos = stripos($url, "://")) !== false) {
        $subPos = $pos + 3;
    }
    if(($pos = stripos($url, "www.", $subPos)) !== false) {
        $subPos = $pos + 4;
    }
    $subStr = strtolower(substr($url, $subPos));
    if(!in_array($subStr, $uniqueUrls)) {
        $uniqueUrls[] = $subStr;
    }
}

var_dump($uniqueUrls);

另一个性能优化可能是在唯一 url 上实施二进制搜索,因为 'in_array' 搜索整个数组,因为它没有排序。

<?php 

$urls = [
    'http://google.com',
    'https://google.com',
    'http://www.google.com',
    'https://www.google.com',
    'www.google.com',
    'google.com',
    'testing.com:9200'
];

$uniqueUrls = [];

foreach ($urls as $url) {
    $urlData = parse_url($url);
    $urlHostName = array_key_exists('host',$urlData) ? $urlData['host'] : $urlData['path'];
    $host = str_replace('www.', '', $urlHostName);
    if(!in_array($host, $uniqueUrls) && $host != ''){
        array_push($uniqueUrls, $host);
    }
}
print_r($uniqueUrls);

?>

为什么每次都要规范化结果数组?

这里有一个更好的代码解决方案:

public static function array_unique_url(array $array): array
{
    $uniqueArray = [];
    foreach ($array as $item) {
        if (!isset($uniqueArray[$item])) {
            $uniqueArray[$item] = self::normalizeUrl($item);
        }
    }

    return $uniqueArray;
}

public static function normalizeUrl(string $url)
{
    return preg_replace('#^(https?://)?(www.)?#', '', strtolower($url));
}

如果您想要原创商品,可以使用 array_keys(array_unique_url($array))

对于您不需要的规范化网址 array_keys

试试这个最简单的解决方案。这里我们使用两个函数 preg_replaceparse_url 来实现所需的输出

Try this code snippet here

<?php

$urls = array(
    "http://google.com",
    "https://google.com",
    "http://www.google.com",
    "https://www.google.com",
    "www.google.com",
    "google.com"
);

$uniqueUrls=array();
foreach($urls as $url)
{
    $changedUrl=  preg_replace("/^(https?:\/\/)?/", "http://", $url);//adding http to urls which does not contains.
    $domain=  preg_replace("/^(www\.)?/","",parse_url($changedUrl,PHP_URL_HOST));//getting the desired host and then removing its www.
    preg_match("/^[a-zA-Z0-9]+/", $domain,$matches);//filtering on the basis of domains
    $uniqueUrls[$matches[0]]=$domain;
}
print_r(array_values($uniqueUrls));