Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sorting 鸽子函数:在排序列表中插入x的位置_Sorting_Wolfram Mathematica - Fatal编程技术网

Sorting 鸽子函数:在排序列表中插入x的位置

Sorting 鸽子函数:在排序列表中插入x的位置,sorting,wolfram-mathematica,Sorting,Wolfram Mathematica,假设我有一个分类清单 {thing1, thing2, thing3, ...} 还有一个二进制比较函数,它表示一个事物是否应该以这种排序顺序排在另一个之前。(我之所以说“东西”,是因为它们不必是数字;它们可以是任意的数据结构。) 我现在寻找一个 一份有序的清单 比较函数,以及 一件事 并返回列表中应插入新对象的第一对相邻对象。 也就是说,返回第一个相邻对{a,b},使comp(a,x)和comp(x,b)为真,其中comp()是比较函数 比如说, pigeon[{1,3,5,7}, Le

假设我有一个分类清单

{thing1, thing2, thing3, ...}
还有一个二进制比较函数,它表示一个事物是否应该以这种排序顺序排在另一个之前。(我之所以说“东西”,是因为它们不必是数字;它们可以是任意的数据结构。)

我现在寻找一个

  • 一份有序的清单
  • 比较函数,以及
  • 一件事
并返回列表中应插入新对象的第一对相邻对象。 也就是说,返回第一个相邻对{a,b},使comp(a,x)和comp(x,b)为真,其中comp()是比较函数

比如说,

pigeon[{1,3,5,7}, Less, 4]
应该回来

{3,5}
(编辑:如果给定的元素小于列表的第一个元素a,则返回{Null,a}。同样,如果它大于最后一个元素z,则返回{z,Null}。此外,我们需要假设比较函数对于两个相同的元素返回true(即,它类似于LessEqual而不是less)或者,物品列表中不包含被归档的物品。感谢高性能标记捕捉到了这一点!)

我的第一个想法是使用Split,然后分别获取结果的两个子列表中的最后一个子列表和第一个子列表。
我会把它作为一个答案发布(或者你可以随意告诉我),但我认为有一种更有效或更优雅的方法。

已经很晚了,下面是部分指定函数的部分解决方案:

f[l_List, compFun_Symbol, el_] := 
 Sort[l, compFun] /. {a___, b_ /; compFun[b, el], 
    c_ /; compFun[el, c], d___} -> {b, c}
我不要求对提供给函数
f
的列表进行排序,因为输入参数包括比较函数。只要(a)元素
el
不是
l
的成员,并且(b)元素
l
中存在排序为
el
左右的元素,此函数就可以正常工作。它可能不适用于
LessEqual
GreaterEqual

如果您想澄清当(a)和(b)中的一个或两个都不满足时,您希望函数返回什么,我很乐意在上午再看一看

编辑:

我认为这符合修订后的要求。与以前一样,它不要求输入列表已经排序

f2[l_List, compFun_, el_] := Sort[Append[l, el], compFun] /. 
{a___, el, b___} :> {If[{a}==={}, Null, Last@{a}], If[{b}==={}, Null, First@{b}]}
我将让其他人来判断这个解决方案的优雅性和效率(我可以看到后一方面的一些明显改进)。现在开始工作。

一种可能的方法:

lst = {1, 3, 5, 7, 9, 11}

{Last@#1, First@#2} & @@ GatherBy[lst, Less[4, #] &]
输出={3,5}

或者,SplitBy可以代替GatherBy

使用二进制搜索 假设:列表中没有重复的元素

BinarySearch有另一种形式:

BinarySearch[l,k,f]
gives the position of k in the list obtained from l by applying f to 
each element in l.  
如果您的列表按上述“f”的结果排序,则可以使用该选项

清除[“全局”*”];需要[“组合”];
ret[list_,f_,elem_]:=模块[{pos,last},
pos[l,e,g]:=IntegerPart[BinarySearch[l,g[e],g];
{
列表[[pos[list,elem,f]]]/.list->Null,
如果[(最后=位置[列表,元素,f]+1)>Length@list,空,列表[[上次]]]
}
]  
a={1,2,3,4,5};
b=选择排序[a,Cos[#1]
下面是一个使用Select(注意第三个参数)的解决方案,该解决方案最多只需通过列表一次,当它找到鸽子洞时停止:

pigeon[l_, f_, x_] := Module[{p, r},
  p = Null;
  r = Select[l, If[f[x,#], True, p = #; False]&, 1];
  If[r==={}, {Last@l, Null}, {p, First@r}]]
示例:

> pigeon[{1,3,5,7}, LessEqual, 4]
{3, 5}

> pigeon[{1,3,5,7}, LessEqual, 0]
{Null, 1}

> pigeon[{1,3,5,7}, LessEqual, 9]
{7, Null}

下面是另一个二进制搜索答案:

(* Helper for pigeon. Additional arguments a and b give current bounds on the 
   indices of the pigeonhole. *)
pigeon0[l_, f_, x_, a_, b_] := Which[
  b-a==1,                    {l[[a]], l[[b]]},
  f[x, l[[Floor[(a+b)/2]]]], pigeon0[l, f, x, a, Floor[(a+b)/2]],
  True,                      pigeon0[l, f, x, Floor[(a+b)/2], b]]

pigeon[l_, f_, x_] := Which[
  f[x, First@l],                 {Null, First@l},
  f[Last@l, x] && !f[x, Last@l], {Last@l, Null},
  True,                          pigeon0[l, f, x, 1, Length@l]]
我这样试过:

> l = Sort@RandomReal[{0,1}, {10^6}];
> pigeon[l, LessEqual, .5]
{0.4999991874459364, 0.5000000938493356}
Needs["Combinatorica`"]
pigeon[list_, func_, 
  x_] := (Join[{Null}, 
    list, {Null}])[[Select[{# - 1/2, #, # + 1/2} &@
      BinarySearch[list, 0, 
       Piecewise[{{0, # == x}, {-1, func[#, x]}, {1, True}}] &], 
     IntegerQ] + 1]]
这与我的另一个答案(带有Select的答案)相匹配,但速度要快得多

其他例子:

> pigeon[{1,3,5,7}, LessEqual, 4]
{3, 5}

> pigeon[{1,3,5,7}, LessEqual, 0]
{Null, 1}

> pigeon[{1,3,5,7}, LessEqual, 9]
{7, Null}

我认为这是一个很好的解决方案:

Needs["Combinatorica`"]
pigeon[list_, func_, x_] := 
  Join[{Null}, list, {Null}]
    [[ {# - 1/2, # + 1/2}& @
     BinarySearch[list, 0.5, 
      Piecewise[{{0, func[#, x]}, {1, True}}] &] + 1 ]]
给予:

> pigeon[{1, 3, 5, 7}, LessEqual, 0]
{Null, 1}

> pigeon[{1, 3, 5, 7}, LessEqual, 3]
{3, 5}

> pigeon[{1, 3, 5, 7}, LessEqual, 4]
{3, 5}

> pigeon[{1, 3, 5, 7}, LessEqual, 9]
{7, Null}
解释:在BinarySearch中对列表{1,3,5,7}应用分段函数,以检查哪些元素不连续,BinarySearch将查找此标记结尾的位置,并返回相关元素。这个实现只使用BinarySearch,所以它应该非常有效

此函数可以很容易地更改为在第二种情况下返回{1,3}。
或者,如果“x”可以是“list”的一个元素,则如下所示:

> l = Sort@RandomReal[{0,1}, {10^6}];
> pigeon[l, LessEqual, .5]
{0.4999991874459364, 0.5000000938493356}
Needs["Combinatorica`"]
pigeon[list_, func_, 
  x_] := (Join[{Null}, 
    list, {Null}])[[Select[{# - 1/2, #, # + 1/2} &@
      BinarySearch[list, 0, 
       Piecewise[{{0, # == x}, {-1, func[#, x]}, {1, True}}] &], 
     IntegerQ] + 1]]
将提供:

> pigeon[{1, 3, 5, 7}, LessEqual, 3]
{3}

啊,谢谢你指出了不足的规格!我澄清了这个问题。你的第二个答案中的比较函数发生了什么变化?(如果你误解了我的“假设它是一个‘小于或等于’的函数”,那可能是我的错。我澄清了问题中的澄清。)另见我对贝里萨利斯的评论。这是一个很酷的方法;谢谢是的,我以这样一种方式解释了您最初的澄清,即我放弃了比较运算符。对你来说,把它放回去应该不会太难。酷,好吧,我编辑它是为了把compFun放回去(在我做的时候稍微压缩一下)。很好!我认为Split应该比Gather更有效,因为Split只考虑相邻元素,因此只需进行一次传递。当然,这也是浪费。一旦我们找到想要返回的相邻对,我们就应该停止遍历列表。我现在喜欢选择更好的,因为O(n)算法。或者可能是模式匹配解决方案;还不确定。吹毛求疵:我不确定你的回答是否足够笼统。可能是我的错。请参阅我对High Performance Mark的评论。您是否假设列表的排序顺序与比较函数一致?@Yaroslav,是的。请随意编辑这个问题,让它更清楚。非常感谢你的回答,贝里萨利斯。是否应该忽略“编辑II”以上的所有内容?如果是这样的话,也许可以删除它,这样答案会更简洁,因为编辑历史记录会被保留。很酷,再次感谢!吹毛求疵:我的意思是比较函数是一个从交叉到布尔的二进制函数。另外,您确定需要关于没有重复元素的假设吗?