Asked  7 Months ago    Answers:  5   Viewed   31 times

How can I search and find, for a given target value, the closest value in an array?

Let's say I have this exemplary array:

array(0, 5, 10, 11, 12, 20)

For example, when I search with the target value 0, the function shall return 0; when I search with 3, it shall return 5; when I search with 14, it shall return 12.

 Answers

77

Pass in the number you're searching for as the first parameter and the array of numbers to the second:

function getClosest($search, $arr) {
   $closest = null;
   foreach ($arr as $item) {
      if ($closest === null || abs($search - $closest) > abs($item - $search)) {
         $closest = $item;
      }
   }
   return $closest;
}
Wednesday, March 31, 2021
 
MassiveAttack
answered 7 Months ago
82

I think (and you have confirmed) that you can represent your data as an XML structure. I this case, you can use XPath to find any branch in your data. Here is sample XML data inferred from your question:

<?xml version="1.0" encoding="utf-8" ?>
<stmt_echo>
    <subnodes>
        <exprs>
            <expr_constfetch>
                <subnodes>
                    <name>
                        <name>
                            <subnodes>
                                <parts>
                                    <part>true</part>
                                    <!-- more items -->
                                </parts>
                            </subnodes>
                        </name>
                    </name>
                </subnodes>
            </expr_constfetch>
            <!-- more items -->
        </exprs>
    </subnodes>
</stmt_echo>

And here is the PHP code to locate the node you mentioned:

$doc = new DOMDocument;
$doc->Load("test.xml");

$xpath = new DOMXPath($doc);
$nodes = $xpath->query("//subnodes/parts[part='true']");

foreach($nodes as $node) {
    dumpNodePath($node);
}

# Output
# /stmt_echo/subnodes/exprs/expr_constfetch/subnodes/name/name/subnodes/parts

function dumpNodePath($node) {
    $path = array($node->tagName);
    while ($node = $node->parentNode) {
        if ($node->nodeType != XML_DOCUMENT_NODE) {
            $path[] = $node->tagName;
        }
    }
    echo "/" . implode("/", array_reverse($path)) . "n";
}
Friday, May 28, 2021
 
max_
answered 5 Months ago
59

Can never avoid the loop :-)

function search($array, $searchString){
   foreach($array as $key=>$val){
        if(in_array($searchString, $val)) return true;
   }
   return false;
}

//use it like so:
if(search($array, '109.148.183.1')){/*do something*/}
Saturday, May 29, 2021
 
DaveRandom
answered 5 Months ago
35

EDIT: Have adjusted the queries below to convert to using long arithmetic, so that we avoid overflow issues.

I would probably use MoreLINQ's MinBy method:

var nearest = array.MinBy(x => Math.Abs((long) x - targetNumber));

Or you could just use:

var nearest = array.OrderBy(x => Math.Abs((long) x - targetNumber)).First();

... but that will sort the whole collection, which you really don't need. It won't make much difference for a small array, admittedly... but it just doesn't feel quite right, compared with describing what you're actually trying to do: find the element with the minimum value according to some function.

Note that both of these will fail if the array is empty, so you should check for that first.

Wednesday, June 9, 2021
 
Gersom
answered 5 Months ago
48

This will give you the starting indices of all such subsequences:

n = 4;
indices = find(conv(double(diff(A)>0), ones(1,n-1), 'valid')==n-1);

Example:

A = [8 9 1 3 7 18 9 10 11 12 5];

produces

indices =
     3     7

So the subsequences would be A(indices(1) + (0:n-1)), A(indices(2) + (0:n-1)), etc:

>> A(indices(1) + (0:n-1))
ans =
     1     3     7    18

>> A(indices(2) + (0:n-1))
ans =
     9    10    11    12
Saturday, August 21, 2021
 
mgraph
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :