I'm trying to implement a MYSQL function MY_LEFT_STR(STRING x,INT position) in such a way that
MY_LEFT_STR('HELLO', 4) => returns 'HELL' (same as internal LEFT function)
MY_LEFT_STR('HELLO',-1) => returns 'HELL'
DROP FUNCTION IF EXISTS MY_LEFT_STR;
CREATE FUNCTION MY_LEFT_STR(
in_str VARCHAR(255),
pos INT
)
RETURNS VARCHAR(255)
BEGIN
IF (pos < 0) THEN
RETURN LEFT(in_str,LENGTH(in_str) - pos);
ELSE
RETURN LEFT(in_str,pos);
END IF;
END;
the result is
select left_str('HELLO', 4) as A
, left_str('HELLO',-1) as B
, left('HELLO',length('HELLO')-1) as C
from dual
+-----+-----+-----+
| A | B | C |
+-----+-----+-----+
|HELL |HELLO|HELL |
+-----+-----+-----+
QUESTION What is wrong with my function declaration? (Besides a generall lack of testing for bordercases like MY_LEFT_STR('A',-4) ...
ANSWER: so embarassing ... the answer lies in the double negative for pos=-1 in
RETURN LEFT(in_str,LENGTH(in_str) - pos);
this should be
RETURN LEFT(in_str,LENGTH(in_str) + pos);
Here's a clue: What's the result of LENGTH(in_str) - (-1)?
When pos is negative, then LENGTH(in_str) - pos yields a number longer than the length of the string. So LEFT() is bound to return the whole string, because you're asking for more characters than the total length of the string.
RETURN LEFT(in_str,LENGTH(in_str) - pos);
If pos is negative, won't LENGTH(in_str) - pos give you (for your example):
LENGTH(HELLO) - (-1) = 6?
Closed. This question needs to be more focused. It is not currently accepting answers.
Closed 8 years ago.
Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
So I got asked today what was the best way to find the closes match within a collection.
For example, you've got an array like this:
1, 3, 8, 10, 13, ...
What number is closest to 4?
Collection is numerical, unordered and can be anything. Same with the number to match.
Lets see what we can come up with, from the various languages of choice.
11 bytes in J:
C=:0{]/:|#-
Examples:
>> a =: 1 3 8 10 13
>> 4 C a
3
>> 11 C a
10
>> 12 C a
13
my breakdown for the layman:
0{ First element of
] the right argument
/: sorted by
| absolute value
# of
- subtraction
Shorter Python: 41 chars
f=lambda a,l:min(l,key=lambda x:abs(x-a))
My attempt in python:
def closest(target, collection) :
return min((abs(target - i), i) for i in collection)[1]
Groovy 28B
f={a,n->a.min{(it-n).abs()}}
Some C# Linq ones... too many ways to do this!
decimal[] nums = { 1, 3, 8, 12 };
decimal target = 4;
var close1 = (from n in nums orderby Math.Abs(n-target) select n).First();
var close2 = nums.OrderBy(n => Math.Abs(n - target)).First();
Console.WriteLine("{0} and {1}", close1, close2);
Even more ways if you use a list instead, since plain ol arrays have no .Sort()
Assuming that the values start in a table called T with a column called N, and we are looking for the value 4 then in Oracle SQL it takes 59 characters:
select*from(select*from t order by abs(n-4))where rownum=1
I've used select * to reduce the whitespace requirements.
Because I actually needed to do this, here is my PHP
$match = 33;
$set = array(1,2,3,5,8,13,21,34,55,89,144,233,377,610);
foreach ($set as $fib)
{
$diff[$fib] = (int) abs($match - $fib);
}
$fibs = array_flip($diff);
$closest = $fibs[min($diff)];
echo $closest;
PostgreSQL:
select n from tbl order by abs(4 - n) limit 1
In the case where two records share the same value for "abs(4 - id)" the output would be in-determinant and perhaps not a constant. To fix that I suggest something like the untested guess:
select n from tbl order by abs(4 - n) + 0.5 * 4 > n limit 1;
This solution provides performance on the order of O(N log N), where O(log N) is possible for example: https://stackoverflow.com/a/8900318/1153319
Ruby like Python has a min method for Enumerable so you don't need to do a sort.
def c(value, t_array)
t_array.min{|a,b| (value-a).abs <=> (value-b).abs }
end
ar = [1, 3, 8, 10, 13]
t = 4
c(t, ar) = 3
Language: C, Char count: 79
c(int v,int*a,int A){int n=*a;for(;--A;++a)n=abs(v-*a)<abs(v-n)?*a:n;return n;}
Signature:
int closest(int value, int *array, int array_size);
Usage:
main()
{
int a[5] = {1, 3, 8, 10, 13};
printf("%d\n", c(4, a, 5));
}
Scala (62 chars), based on the idea of the J and Ruby solutions:
def c(l:List[Int],n:Int)=l.sort((a,b)=>(a-n).abs<(b-n).abs)(0)
Usage:
println(c(List(1,3,8,10,13),4))
PostgreSQL:
This was pointed out by RhodiumToad on FreeNode and has performance on the order of O(log N)., much better then the other PostgreSQL answer here.
select * from ((select * from tbl where id <= 4
order by id desc limit 1) union
(select * from tbl where id >= 4
order by id limit 1)) s order by abs(4 - id) limit 1;
Both of the conditionals should be "or equal to" for much better handling of the id exists case. This also has handling in the case where two records share the same value for "abs(4 - id)" then that other PostgreSQL answer here.
The above code doesn't works for floating numbers.
So here's my revised php code for that.
function find_closest($match, $set=array()) {
foreach ($set as $fib) {
$diff[$fib] = abs($match - $fib);
}
return array_search(min($diff), $diff);
}
$set = array('2.3', '3.4', '3.56', '4.05', '5.5', '5.67');
echo find_closest(3.85, $set); //return 4.05
Python by me and https://stackoverflow.com/users/29253/igorgue based on some of the other answers here. Only 34 characters:
min([(abs(t-x), x) for x in a])[1]
Haskell entry (tested):
import Data.List
near4 = head . sortBy (\n1 n2 -> abs (n1-4) `compare` abs (n2-4))
Sorts the list by putting numbers closer to 4 near the the front. head takes the first element (closest to 4).
Ruby
def c(r,t)
r.sort{|a,b|(a-t).abs<=>(b-t).abs}[0]
end
Not the most efficient method, but pretty short.
returns only one number:
var arr = new int[] { 1, 3, 8, 10, 13 };
int numToMatch = 4;
Console.WriteLine("{0}",
arr.OrderBy(n => Math.Abs(numToMatch - n)).ElementAt(0));
returns only one number:
var arr = new int[] { 1, 3, 8, 10, 13 };
int numToMatch = 4;
Console.WriteLine("{0}",
arr.Select(n => new{n, diff = Math.Abs(numToMatch - n) }).OrderBy(x => x.diff).ElementAt(0).n);
Perl -- 66 chars:
perl -e 'for(qw/1 3 8 10 13/){$d=($_-4)**2; $c=$_ if not $x or $d<$x;$x=$d;}print $c;'
EDITED = in the for loop
int Closest(int val, int[] arr)
{
int index = 0;
for (int i = 0; i < arr.Length; i++)
if (Math.Abs(arr[i] - val) < Math.Abs(arr[index] - val))
index = i;
return arr[index];
}
Here's another Haskell answer:
import Control.Arrow
near4 = snd . minimum . map (abs . subtract 4 &&& id)
Haskell, 60 characters -
f a=head.Data.List.sortBy(compare`Data.Function.on`abs.(a-))
Kdb+, 23B:
C:{x first iasc abs x-}
Usage:
q)a:10?20
q)a
12 8 10 1 9 11 5 6 1 5
q)C[a]4
5
Python, not sure how to format code, and not sure if code will run as is, but it's logic should work, and there maybe builtins that do it anyways...
list = [1,4,10,20]
num = 7
for lower in list:
if lower <= num:
lowest = lower #closest lowest number
for higher in list:
if higher >= num:
highest = higher #closest highest number
if highest - num > num - lowest: # compares the differences
closer_num = highest
else:
closer_num = lowest
In Java Use a Navigable Map
NavigableMap <Integer, Integer>navMap = new ConcurrentSkipListMap<Integer, Integer>();
navMap.put(15000, 3);
navMap.put(8000, 1);
navMap.put(12000, 2);
System.out.println("Entry <= 12500:"+navMap.floorEntry(12500).getKey());
System.out.println("Entry <= 12000:"+navMap.floorEntry(12000).getKey());
System.out.println("Entry > 12000:"+navMap.higherEntry(12000).getKey());
int numberToMatch = 4;
var closestMatches = new List<int>();
closestMatches.Add(arr[0]); // closest tentatively
int closestDifference = Math.Abs(numberToMatch - arr[0]);
for(int i = 1; i < arr.Length; i++)
{
int difference = Math.Abs(numberToMatch - arr[i]);
if (difference < closestDifference)
{
closestMatches.Clear();
closestMatches.Add(arr[i]);
closestDifference = difference;
}
else if (difference == closestDifference)
{
closestMatches.Add(arr[i]);
}
}
Console.WriteLine("Closest Matches");
foreach(int x in closestMatches) Console.WriteLine("{0}", x);
Some of you don't seem to be reading that the list is unordered (although with the example as it is I can understand your confusion). In Java:
public int closest(int needle, int haystack[]) { // yes i've been doing PHP lately
assert haystack != null;
assert haystack.length; > 0;
int ret = haystack[0];
int diff = Math.abs(ret - needle);
for (int i=1; i<haystack.length; i++) {
if (ret != haystack[i]) {
int newdiff = Math.abs(haystack[i] - needle);
if (newdiff < diff) {
ret = haystack[i];
diff = newdiff;
}
}
}
return ret;
}
Not exactly terse but hey its Java.
Common Lisp using iterate library.
(defun closest-match (list n)
(iter (for i in list)
(finding i minimizing (abs (- i n)))
41 characters in F#:
let C x = Seq.min_by (fun n -> abs(n-x))
as in
#light
let l = [1;3;8;10;13]
let C x = Seq.min_by (fun n -> abs(n-x))
printfn "%d" (C 4 l) // 3
printfn "%d" (C 11 l) // 10
printfn "%d" (C 12 l) // 13
Ruby. One pass-through. Handles negative numbers nicely. Perhaps not very short, but certainly pretty.
class Array
def closest int
diff = int-self[0]; best = self[0]
each {|i|
if (int-i).abs < diff.abs
best = i; diff = int-i
end
}
best
end
end
puts [1,3,8,10,13].closest 4