这是受到我遇到的一个现实世界问题的启发。我很好奇,看看是否有任何聪明的方法可以解决这个问题。
给您两个未排序的数组A和B,每个数组包含任意数量的浮点数。A和B的长度不一定相同。编写一个函数,该函数顺序获取A的元素并在数组B中找到最接近的值。结果必须包含在新数组中。
获胜条件
最短的代码获胜(照常)。
这是受到我遇到的一个现实世界问题的启发。我很好奇,看看是否有任何聪明的方法可以解决这个问题。
给您两个未排序的数组A和B,每个数组包含任意数量的浮点数。A和B的长度不一定相同。编写一个函数,该函数顺序获取A的元素并在数组B中找到最接近的值。结果必须包含在新数组中。
获胜条件
最短的代码获胜(照常)。
Answers:
(UTF-8中为21个字节)
B[{↑⍋|⍵-B}¨A]
如果要使用真正的lambda(A作为左参数,B作为右参数):
{⍵[⍺{↑⍋|⍺-⍵}¨⊂⍵]}
{...}¨A
{...}
使用每个A值调用lambda函数(而不是使用A作为数组调用),将结果收集到相同形状的数组中
|⍵-B
计算参数⍵与B中所有变量之间的差的绝对值(-是减法,|是abs)。
↑⍋
获取最小元素的索引(⍋对返回索引的数组进行排序,↑获取第一个元素)
B[...]
只是按索引获取元素。
该解决方案非常简单,尽管它使用了APL排序功能的奇妙功能,该功能返回置换向量(原始数组中排序元素的索引),而不是排序数组本身。
#&@@@Nearest@A/@B
它是如何工作的?是的,我承认这里有些作弊,因为Mathematica具有内置的最近功能。其余的很简单,并且关心将结果排列在一维数组中。看起来丑陋只是因为要使其简短而付出的额外努力。
我不确定我是否正确理解了这个问题,但是无论如何这是我的解决方案。
我使用列表而不是数组,因为它使我可以编写较短的代码。
整数数组比整数列表短。
输入:
t(new int[] { 0, 25, 10, 38 }, new int[] { 3, 22, 15, 49, 2 });
方法:
void t(int[]a,int[]b){var e=a.Select(c=>b.OrderBy(i=>Math.Abs(c-i)).First()).ToArray();
输出:
2, 22, 15, 49
如果我的回答不正确,请在下面留下评论。
编辑: @grax指出,现在的问题是关于浮点数。因此,我也想包括他的答案。
float[]t(float[]a,float[]b){return a.Select(d=>b.OrderBy(e=>Math.Abs(e-d)).First()).ToArray();}
item
为i
,您将可以确保另外6个字符的安全;)
float[] t(float[] a, float[] b) {return a.Select(d=>b.OrderBy(e=>Math.Abs(e-d)).First()).ToArray();}
B[apply(abs(outer(A,B,`-`)),1,which.min)]
说明:
outer(A,B,`-`)
为A的每个元素x计算差异x-B
,并将结果输出为矩阵(尺寸为length(A)x length(B))。
which.min
选择最小数字的索引。在矩阵的每行上
apply(x, 1, f)
应用函数。
因此返回A的每个元素与向量B的元素之间的最小绝对差的索引。f
x
apply(abs(outer(A,B,`-`)),1,which.min)
用法:
> A <- runif(10,0,50)
> B <- runif(10,0,50)
> A
[1] 10.0394987 23.4564467 19.6667152 36.7101256 47.4567670 49.8315028 2.1321263 19.2866901 0.7668489 22.5539178
> B
[1] 44.010174 32.743469 1.908891 48.222695 16.966245 23.092239 24.762485 30.793543 48.703640 6.935354
> B[apply(abs(outer(A,B,`-`)),1,which.min)]
[1] 6.935354 23.092239 16.966245 32.743469 48.222695 48.703640 1.908891 16.966245 1.908891 23.092239
q~
f{{1$-z}$0=\;}
p
主要代码在第二行,其余代码用于使用标准输入和漂亮输出。
说明:
q~
读取并评估输入
f{...}
,为第一个数组的每个元素和下一个对象(即第二个数组)的每个块执行该块,将结果收集到一个数组中
{...}$
,然后使用该块对第二个数组进行排序,以计算出每个项目的键值
1$
复制当前第一个数组中的项目
-z
减去然后取绝对值
0=
,将排序后的数组的第一个值(具有最小键的
\;
那个)丢弃,第一个数组中的项目丢弃,并
p
打印结果的字符串表示形式
例子(从其他答案中得到启发):
输入:[10.1 11.2 12.3 13.4 9.5] [10 12 14]
输出:[10 12 12 14 10]
输入:[0 25 10 38] [3 22 15 49 2]
输出:[2 22 15 49]
最小化距离。使用正方形而不是abs可以节省字符。
编辑代数...
编辑无用的赋值(不带功能定义的测试的其余部分)
F=(A,B)=>A.map(a=>B.sort((x,y)=>x*x-y*y+2*a*(y-x))[0])
是 F=(A,B)=>D=A.map(a=>B.sort((x,y)=>((x-=a,y-=a,x*x-y*y))[0])
测试
F([10.1, 11.2, 12.3, 13.4, 9.5],[10, 12, 14])
结果: [10, 12, 12, 14, 10]
D=
不需要,因为会map
返回一个新数组。替代(相同长度)的排序功能:(x,y)=>(x-=a)*x-(y-=a)*y
f=lambda a,b:[min((abs(x-n),x)for x in b)[1]for n in a]
a
和b
是输入数组,而所需的数组是表达式的结果。
c a b=[[y|y<-b,(y-x)^2==minimum[(z-x)^2|z<-b]]!!0|x<-a]
最初,我想使用minimumBy
和comparing
,但是由于这些不在Prelude中,因此花了很多字符才能使它们合格。还从其他答案中窃取了平方的想法以剃除角色。
∟A+seq(min(∟B+i²∟A(N)),N,1,dim(∟A
与APL不太接近,但是使用的功能较弱-它不使用“排序依据”或“最小索引”功能。TI-BASIC的缺点是缺少这些功能和多维数组。
取消高尔夫:
seq( ,N,1,dim(∟A #Sequence depending on the Nth element of list A
∟A(N)+min( +0i) #Number with minimum absolute value, add to ∟A(N)
∟B-∟A(N) #Subtracts Nth element of ∟A from all elements of B
min(函数有两种行为:与实数或列表一起使用时,它给出最小值;但是,与复数或列表一起使用时,它给出绝对值最小的值。加0i
或乘以i^2
使解释器得出使用第二种行为,因此min(1,-2)
return,-2
而min(1+0i,-2+0i)
return 1
。
function f();integer::f(size(a));f(:)=[(b(minloc(abs(a(i)-b))),i=1,size(a))];endfunction
这要求contain
在完整程序中进行编辑:
program main
real :: a(5), b(3)
integer :: i(size(a))
a = [10.1, 11.2, 12.3, 13.4, 9.5]
b = [10, 12, 14]
i = f()
print*,i
contains
function f()
integer :: f(size(a))
f(:)=[(b(minloc(abs(a(i)-b))),i=1,size(a))]
end function
end program main
方括号声明一个数组,而while (...,i=)
表示隐式do
循环;然后,我返回b
为其a(i)-b
最小化的元素的值。
#define f float
f T, *C, m;
f *q(f *A, f *B, int S, f s)
{
if(m)
return abs(T - *A) - abs(T - *B);
for (
C = malloc(S * 4);
m = S--;
C[S] = *B
)
T = A[S],
qsort(B, s, 4, q);
return C;
}
好的,我认为这个小代码需要解释。
起初,我尝试使用两个级别的for循环来完成此工作,以找到最小差并将当前值设置为B值的最小值。这是非常基本的。
使用qsort和比较器功能可以达到相同的目的。我根据差异而不是B的元素将其排序为B。这么少的算法功能太多。因此,函数q现在有两个作用。首先,它是算法本身,其次是(当qsort调用时)比较器。为了两国之间的交流,我必须声明全局变量。
m表示它处于比较器状态还是主状态。
例:
float A[] = {1.5, 5.6, 8.9, -33.1};
float B[] = {-20.1, 2.2, 10.3};
float *C;
C = q(A, B, sizeof(A)/sizeof(*A), sizeof(B)/sizeof(*B));
// C holds 2.2,2.2,10.3,-20.1
注意:这是部分解决方案。我正在努力使其成为一个完整的解决方案
{{\.@\.[.,,\]zip@{[\~@-abs]}+%{~\;}$0=0==}%\;}:f;
是。GolfScript确实支持浮点。在这里尝试。例:
# B is [-20.1 2.2 10.3]
[-201 10 -1?*
22 10 -1?*
103 10 -1?*]
# A. No floating point numbers allowed here.
# This is because 1.5{}+ (where the 1.5 is a
# single floating point number, not 1.5,
# which would be 1 1 5) results in the block
# {1.5 }, which leads to 1 1 5 when executed
[1 5 9 -30]
输出:
[2.2 2.2 10.3 -20.1]
程序找到最小的差异,并从数组B中保存最接近的值。我将很快打高尔夫球。
List<float> F(List<float> a, List<float> b)
{
List<float> c = new List<float>();
float diff,min;
int k;
for(int i=0; i<a.Count;i++)
{
diff=0;
min=1e6F;
k = 0;
for(int j=0; j<b.Count;j++)
{
diff = Math.Abs(a[i] - b[j]);
if (diff < min)
{
min = diff;
k = j;
}
}
c.Add(b[k]);
}
return c;
}
带有测试代码的完整程序
using System;
using System.Collections.Generic;
public class JGolf
{
static List<float> NearestValues(List<float> a, List<float> b)
{
List<float> c = new List<float>();
float diff,min;
int k;
for(int i=0; i<a.Count;i++)
{
diff=0;
min=1e6F;
k = 0;
for(int j=0; j<b.Count;j++)
{
diff = Math.Abs(a[i] - b[j]);
if (diff < min)
{
min = diff;
k = j;
}
}
c.Add(b[k]);
}
return c;
}
public static void Main(string[] args)
{
List<float> A = RandF(8413);
Console.WriteLine("A");
Print(A);
List<float> B = RandF(9448);
Console.WriteLine("B");
Print(B);
List<float> d = JGolf.NearestValues(A, B);
Console.WriteLine("d");
Print(d);
Console.ReadLine();
}
private static List<float> RandF(int seed)
{
Random r = new Random(seed);
int n = r.Next(9) + 1;
List<float> c = new List<float>();
while (n-- > 0)
{
c.Add((float)r.NextDouble() * 100);
}
return c;
}
private static void Print(List<float> d)
{
foreach(float f in d)
{
Console.Write(f.ToString()+", ");
}
}
}