php 通过属性在数组中搜索对象的有效方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7106772/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 02:01:35  来源:igfitidea点击:

efficient way to search object in an array by a property

phparrays

提问by André Al?ada Padez

well, having something like:

好吧,有类似的东西:

$array[0]->id = 'one';
$array[0]->color = 'white';
$array[1]->id = 'two';
$array[1]->color = 'red';
$array[2]->id = 'three';
$array[2]->color = 'blue';

what would be the fastest, most efficient way to implement a method like

实现类似方法的最快、最有效的方法是什么?

function findObjectById($id){}

函数 findObjectById($id){}

that would return the object $array[0] if i called:

如果我调用,它将返回对象 $array[0]:

$obj = findObjectById('one')

and would return false if i passed 'four' as a param.

如果我将“四”作为参数传递,则会返回 false。

采纳答案by hsz

You can iterate that objects:

您可以迭代该对象:

function findObjectById($id){
    $array = array( /* your array of objects */ );

    foreach ( $array as $element ) {
        if ( $id == $element->id ) {
            return $element;
        }
    }

    return false;
}

Edit:

编辑:

Faster way is to have an array with keys equals to objects' ids (if unique);

更快的方法是让数组的键等于对象的 id(如果唯一);

Then you can build your function as follow:

然后您可以按如下方式构建您的功能:

function findObjectById($id){
    $array = array( /* your array of objects with ids as keys */ );

    if ( isset( $array[$id] ) ) {
        return $array[$id];
    }

    return false;
}

回答by Saad Imran.

Well, you would would have to loop through them and check compare the ID's unless your array is sorted (by ID) in which case you can implement a searching algorithm like binary search or something of that sort to make it quicker.

好吧,除非您的数组已排序(按 ID),否则您将不得不遍历它们并检查比较 ID,在这种情况下,您可以实现诸如二分搜索之类的搜索算法以使其更快。

My suggestion would be to first sort the arrays using a sorting algorithm (binary sort, insertion sort or quick sort) if the array is not sorted already. Then you can implement a search algorithm which should improve performance and I think that's as good as it gets.

如果数组尚未排序,我的建议是首先使用排序算法(二进制排序、插入排序或快速排序)对数组进行排序。然后你可以实现一个应该提高性能的搜索算法,我认为这是最好的。

http://www.algolist.net/Algorithms/Binary_search

http://www.algolist.net/Algorithms/Binary_search

回答by Kaken Bok

The thing with performance of data structures is not only how to get but mostly how to store my data.

数据结构的性能不仅是如何获取,而且主要是如何存储我的数据。

If you are free to design your array, use an associative array:

如果您可以自由设计数组,请使用关联数组:

$array['one']->id = 'one';
$array['one']->color = 'white';
$array['two']->id = 'two';
$array['two']->color = 'red';
$array['three']->id = 'three';
$array['three']->color = 'blue';

Finding is then the most cheap: $one = $array['one];

查找是最便宜的: $one = $array['one];

UPDATE:

更新:

If you cannot modify your array constitution, you could create a separate array which maps ids to indexes. Finding an object this way does not cost any time:

如果您无法修改数组构成,则可以创建一个单独的数组,将 id 映射到索引。以这种方式查找对象不会花费任何时间:

$map['one'] = 0;
$map['two'] = 1;
$map['three'] = 2;
...

getObjectById()then first lookups the index of the id within the original array and secondly returns the right object:

getObjectById()然后首先在原始数组中查找 id 的索引,然后返回正确的对象:

$index = $map[$id];
return $array[$index];

回答by Justin Hyman

This is my absolute favorite algorithm for very quickly finding what I need in a very large array, quickly. It is a Binary Search Algorithmimplementation I created and use extensively in my PHP code. It hands-down beats straight-forward iterative search routines. You can vary it a multitude of ways to fit your need, but the basic algorithm remains the same.

这是我最喜欢的算法,可以在非常大的数组中快速找到我需要的东西。它是我在 PHP 代码中创建并广泛使用的二进制搜索算法实现。它彻底击败了直接的迭代搜索例程。您可以通过多种方式改变它以满足您的需要,但基本算法保持不变。

To use it (this variation), the array must be sorted, by the index you want to find, in lowest-to-highest order.

要使用它(此变体),必须按您要查找的索引按从低到高的顺序对数组进行排序。

function quick_find(&$array, $property, $value_to_find, &$first_index) {
    $l = 0;
    $r = count($array) - 1;
    $m = 0;
    while ($l <= $r) {
        $m = floor(($l + $r) / 2);
        if ($array[$m]->{$property} < $value_to_find) {
            $l = $m + 1;
        } else if ($array[$m]->{$property} > $value_to_find) {
            $r = $m - 1;
        } else {
            $first_index = $m;
            return $array[$m];
        }
    }
    return FALSE;
}

And to test it out:

并测试一下:

/* Define a class to put into our array of objects */
class test_object {
    public $index;
    public $whatever_you_want;
    public function __construct( $index_to_assign ) {
        $this->index = $index_to_assign;
        $this->whatever_you_want = rand(1, 10000000);
    }
}

/* Initialize an empty array we will fill with our objects */
$my_array = array();

/* Get a random starting index to simulate data (possibly loaded from a database) */
$my_index = rand(1256, 30000);

/* Say we are needing to locate the record with this index */
$index_to_locate = $my_index + rand(200, 30234);

/* 
 * Fill "$my_array()" with ONE MILLION objects of type "test_object" 
 * 
 * 1,000,000 objects may take a little bit to generate.  If you don't
 * feel patient, you may lower the number!
 * 
 */
for ($i = 0; $i < 1000000; $i++) {
    $searchable_object = new test_object($my_index); // Create the object
    array_push($my_array, $searchable_object); // Add it to the "$my_array" array
    $my_index++; /* Increment our unique index */
}

echo "Searching array of ".count($my_array)." objects for index: " . $index_to_locate ."\n\n";

$index_found = -1; // Variable into which the array-index at which our object was found will be placed upon return of the function.

$object = quick_find($my_array, "index", $index_to_locate, $index_found);

if ($object == NULL) {
    echo "Index $index_to_locate was not contained in the array.\n";
} else {
    echo "Object found at index $index_found!\n";
    print_r($object);
}
echo "\n\n";

Now, a few notes:

现在,注意几点:

You MAYuse this to find non-unique indexes; the array MUST still be sorted in ascending order. Then, when it finds an element matching your criteria, you must walk the array backwards to find the first element, or forward to find the last. It will add a few "hops" to your search, but it will still most likely be faster than iterating a large array.

可以使用它来查找非唯一索引;数组仍必须按升序排序。然后,当它找到与您的条件匹配的元素时,您必须向后遍历数组以查找第一个元素,或向前查找最后一个元素。它将为您的搜索添加一些“跳跃”,但它仍然很可能比迭代大型数组更快。

For STRING indexes, you can change the arithmetic comparisons (i.e. " > " and " < " ) in quick_find() to PHP's function "strcasecmp()". Just make sure the STRING indexes are sorted the same way (for the example implementation): Alphabetically and Ascending.

对于 STRING 索引,您可以将 quick_find() 中的算术比较(即“>”和“<”)更改为 PHP 的函数“strcasecmp()”。只需确保 STRING 索引的排序方式相同(对于示例实现):按字母顺序和升序。

And if you want to have a version that can search arrays of objects sorted in EITHERascending ORdecending order:

如果你想有一个版本,可以在搜索排序的对象数组无论是上升decending顺序:

function quick_find_a(&$array, $property, $value_to_find, &$first_index) {
    $l = 0;
    $r = count($array) - 1;
    $m = 0;
    while ($l <= $r) {
        $m = floor(($l + $r) / 2);
        if ($array[$m]->{$property} < $value_to_find) {
            $l = $m + 1;
        } else if ($array[$m]->{$property} > $value_to_find) {
            $r = $m - 1;
        } else {
            $first_index = $m;
            return $array[$m];
        }
    }
    return FALSE;
}

function quick_find_d(&$array, $property, $value_to_find, &$first_index) {
    $l = 0;
    $r = count($array) - 1;
    $m = 0;
    while ($l <= $r) {
        $m = floor(($l + $r) / 2);
        if ($value_to_find > $array[$m]->{$property}) {
            $r = $m - 1;
        } else if ($value_to_find < $array[$m]->{$property}) {
            $l = $m + 1;
        } else {
            $first_index = $m;
            return $array[$m];
        }
    }
    return FALSE;
}


function quick_find(&$array, $property, $value_to_find, &$first_index) {
    if ($array[0]->{$property} < $array[count($array)-1]->{$property}) {
        return quick_find_a($array, $property, $value_to_find, $first_index);
    } else {
        return quick_find_d($array, $property, $value_to_find, $first_index);
    }
}

回答by chunime

You can use the function array_searchof php like this

你可以像这样使用php的array_search函数

$key=array_search("one", array_column(json_decode(json_encode($array),TRUE), 'color'));
var_dump($array[$key]);

回答by KoZm0kNoT

Something I like to do in these situations is to create a referential array, thus avoiding having to re-copy the object but having the power to use the reference to it like the object itself.

在这些情况下,我喜欢做的事情是创建一个引用数组,从而避免必须重新复制对象,但可以像对象本身一样使用对它的引用。

$array['one']->id = 'one';
$array['one']->color = 'white';
$array['two']->id = 'two';
$array['two']->color = 'red';
$array['three']->id = 'three';
$array['three']->color = 'blue';

Then we can create a simple referential array:

然后我们可以创建一个简单的引用数组:

$ref = array();
foreach ( $array as $row )
    $ref[$row->id] = &$array[$row->id];

Now we can simply test if an instance exists in the array and even use it like the original object if we wanted:

现在我们可以简单地测试一个实例是否存在于数组中,如果我们愿意,甚至可以像原始对象一样使用它:

if ( isset( $ref['one'] ) )
    echo $ref['one']->color;

would output:

会输出:

white

If the id in question did not exist, the isset() would return false, so there's no need to iterate the original object over and over looking for a value...we just use PHP's isset() function and avoid using a separate function altogether.

如果有问题的 id 不存在,isset() 将返回 false,因此无需一遍又一遍地迭代原始对象以查找值...我们只使用 PHP 的 isset() 函数并避免使用单独的函数共。

Please note when using references that you want use the "&" with the original array and not the iterator, so using &$row would not give you what you want.

请注意,在使用引用时,您希望将“&”与原始数组一起使用,而不是迭代器,因此使用 &$row 不会给您想要的东西。

回答by lacroixca

Here is what I use. Reusable functions that loop through an array of objects. The second one allows you to retrieve a single object directly out of all matches (the first one to match criteria).

这是我使用的。循环遍历对象数组的可重用函数。第二个允许您直接从所有匹配项中检索单个对象(第一个匹配条件的对象)。

function get_objects_where($match, $objects) {
    if ($match == '' || !is_array($match)) return array ();
    $wanted_objects = array ();
    foreach ($objects as $object) {
        $wanted = false;
        foreach ($match as $k => $v) {
            if (is_object($object) && isset($object->$k) && $object->$k == $v) {
                $wanted = true;
            } else {
                $wanted = false;
                break;
            };
        };
        if ($wanted) $wanted_objects[] = $object;
    };
    return $wanted_objects;
};

function get_object_where($match, $objects) {
    if ($match == '' || !is_array($match)) return (object) array ();
    $wanted_objects = get_objects_where($match, $objects);
    return count($wanted_objects) > 0 ? $wanted_objects[0] : (object) array ();
};