- xml - AJAX/Jquery XML 解析
- 具有多重继承的 XML 模式
- .net - 枚举序列化 Json 与 XML
- XML 简单类型、简单内容、复杂类型、复杂内容
在Ruby - Compare two Enumerators elegantly ,据说
The problem with zip is that it creates arrays internally, no matter what Enumerable you pass. There's another problem with length of input params
我查看了 YARV 中 Enumerable#zip 的实现,并看到了
static VALUE
enum_zip(int argc, VALUE *argv, VALUE obj)
{
int i;
ID conv;
NODE *memo;
VALUE result = Qnil;
VALUE args = rb_ary_new4(argc, argv);
int allary = TRUE;
argv = RARRAY_PTR(args);
for (i=0; i<argc; i++) {
VALUE ary = rb_check_array_type(argv[i]);
if (NIL_P(ary)) {
allary = FALSE;
break;
}
argv[i] = ary;
}
if (!allary) {
CONST_ID(conv, "to_enum");
for (i=0; i<argc; i++) {
argv[i] = rb_funcall(argv[i], conv, 1, ID2SYM(id_each));
}
}
if (!rb_block_given_p()) {
result = rb_ary_new();
}
/* use NODE_DOT2 as memo(v, v, -) */
memo = rb_node_newnode(NODE_DOT2, result, args, 0);
rb_block_call(obj, id_each, 0, 0, allary ? zip_ary : zip_i, (VALUE)memo);
return result;
}
我是否正确理解了以下内容?
检查是否所有参数都是数组,如果是,用直接引用替换对数组的一些间接引用
for (i=0; i<argc; i++) {
VALUE ary = rb_check_array_type(argv[i]);
if (NIL_P(ary)) {
allary = FALSE;
break;
}
argv[i] = ary;
}
如果它们不都是数组,则改为创建一个枚举器
if (!allary) {
CONST_ID(conv, "to_enum");
for (i=0; i<argc; i++) {
argv[i] = rb_funcall(argv[i], conv, 1, ID2SYM(id_each));
}
}
只有在没有给定 block 时才创建数组的数组
if (!rb_block_given_p()) {
result = rb_ary_new();
}
如果一切都是数组,使用zip_ary
,否则使用zip_i
,并在每组值上调用一个 block
/* use NODE_DOT2 as memo(v, v, -) */
memo = rb_node_newnode(NODE_DOT2, result, args, 0);
rb_block_call(obj, id_each, 0, 0, allary ? zip_ary : zip_i, (VALUE)memo);
如果没有给出 block ,返回一个数组数组,否则返回 nil (Qnil
)?
return result;
}
最佳答案
我将使用 1.9.2-p0,因为这是我手头上的。
rb_check_array_type
函数如下所示:
VALUE
rb_check_array_type(VALUE ary)
{
return rb_check_convert_type(ary, T_ARRAY, "Array", "to_ary");
}
rb_check_convert_type
看起来像这样:
VALUE
rb_check_convert_type(VALUE val, int type, const char *tname, const char *method)
{
VALUE v;
/* always convert T_DATA */
if (TYPE(val) == type && type != T_DATA) return val;
v = convert_type(val, tname, method, FALSE);
if (NIL_P(v)) return Qnil;
if (TYPE(v) != type) {
const char *cname = rb_obj_classname(val);
rb_raise(rb_eTypeError, "can't convert %s to %s (%s#%s gives %s)",
cname, tname, cname, method, rb_obj_classname(v));
}
return v;
}
注意 convert_type
调用。这看起来很像 C 版本的 Array.try_convert
而 try_convert
恰好看起来像这样:
/*
* call-seq:
* Array.try_convert(obj) -> array or nil
*
* Try to convert <i>obj</i> into an array, using +to_ary+ method.
* Returns converted array or +nil+ if <i>obj</i> cannot be converted
* for any reason. This method can be used to check if an argument is an
* array.
*
* Array.try_convert([1]) #=> [1]
* Array.try_convert("1") #=> nil
*
* if tmp = Array.try_convert(arg)
* # the argument is an array
* elsif tmp = String.try_convert(arg)
* # the argument is a string
* end
*
*/
static VALUE
rb_ary_s_try_convert(VALUE dummy, VALUE ary)
{
return rb_check_array_type(ary);
}
所以,是的,第一个循环是在 argv
中寻找任何不是数组的东西,如果找到这样的东西就设置 allary
标志。
在 enum.c
中,我们看到了这个:
id_each = rb_intern("each");
所以 id_each
是 Ruby each
迭代器方法的内部引用。在 vm_eval.c
中,我们有这个:
/*!
* Calls a method
* \param recv receiver of the method
* \param mid an ID that represents the name of the method
* \param n the number of arguments
* \param ... arbitrary number of method arguments
*
* \pre each of arguments after \a n must be a VALUE.
*/
VALUE
rb_funcall(VALUE recv, ID mid, int n, ...)
所以这样:
argv[i] = rb_funcall(argv[i], conv, 1, ID2SYM(id_each));
正在对 argv[i]
中的任何内容调用 to_enum
(本质上是 default argument)。
因此,第一个 for
和 if
block 的最终结果是 argv
要么充满数组,要么充满枚举器,而不是可能是两者的混合体。但请注意逻辑是如何工作的:如果发现不是数组的东西,那么一切都变成了枚举器。 enum_zip
函数的第一部分会将数组包装在枚举器中(这基本上是免费的,或者至少便宜到不用担心)但不会将枚举器扩展到数组中(这可能非常昂贵)。早期版本可能采用了另一种方式(更喜欢数组而不是枚举数),我将把它留给读者或历史学家作为练习。
下一部分:
if (!rb_block_given_p()) {
result = rb_ary_new();
}
如果调用 zip
时没有 block ,则创建一个新的空数组并将其保留在 result
中。这里我们应该注意什么 zip
returns :
enum.zip(arg, ...) → an_array_of_array
enum.zip(arg, ...) {|arr| block } → nil
如果有一个 block ,那么就没有什么可以返回,result
可以保持为Qnil
;如果没有 block ,那么我们需要在 result
中有一个数组,以便可以返回一个数组。
从 parse.c
中,我们看到 NODE_DOT2
是一个双点范围,但看起来他们只是将新节点用作简单的三元素结构; rb_new_node
只是分配一个对象,设置一些位,并在结构中分配三个值:
NODE*
rb_node_newnode(enum node_type type, VALUE a0, VALUE a1, VALUE a2)
{
NODE *n = (NODE*)rb_newobj();
n->flags |= T_NODE;
nd_set_type(n, type);
n->u1.value = a0;
n->u2.value = a1;
n->u3.value = a2;
return n;
}
nd_set_type
只是一个微不足道的宏。现在我们有了 memo
作为一个三元素结构。 NODE_DOT2
的这种使用似乎是一种方便的拼凑。
rb_block_call
函数似乎是核心内部迭代器。我们再次看到我们的 friend id_each
,所以我们将进行一次 each
迭代。然后我们看到在 zip_i
和 zip_ary
之间进行选择;这是创建内部数组并将其推送到 result
的地方。 zip_i
和 zip_ary
之间的唯一区别似乎是 zip_i
中的 StopIteration 异常处理。
此时我们已经完成了压缩,我们要么在 result
中有数组的数组(如果没有 block ),要么在 中有
(如果有 block )。Qnil
>result
执行摘要:第一个循环明确避免将枚举数扩展为数组。 zip_i
和 zip_ary
调用仅在必须构建数组数组作为返回值时才适用于非临时数组。因此,如果您使用至少一个非数组枚举器调用 zip
并使用 block 形式,那么它一直都是枚举器,而“zip 的问题在于它在内部创建数组”不会发生。回顾 1.8 或其他 Ruby 实现留给读者作为练习。
关于c - Ruby 的 Enumerable#zip 是否在内部创建数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6487747/
挖掘这个,这是一个很酷的 Enumerator(惰性序列)从 1 到(Ruby 可以表示的最大 Float): 1.9.3-p327 :014 > e = (1..Float::INFINITY).e
这个问题在这里已经有了答案: Swift 2.0 : 'enumerate' is unavailable: call the 'enumerate()' method on the sequenc
我不确定这是否特定于 ML.NET,但它确实发生在 ML.NET 的上下文中。 我正在使用 ML.NET 对一些图像进行分类。我意识到,无论我是否对结果 IEnumerable 调用 .ToArray
在Collections Framework中,我们有Iterator和ListIterator接口(interface),它们用于迭代数据结构。它们提供了完整的迭代功能。但我想知道为什么 JDK 在
我正在使用 playframework 的异步 I/O 库,它使用 Iteratees 和 Enumerators。我现在有一个 Iterator[T] 作为数据接收器(为简单起见,说它是一个 Ite
更新: private final java.util.Properties tilesPropertyMap = new Properties(); private class Delegati
所以,我有一个像这样的字符串 \begin{enumerate} \item My first item \item My second item \end{enumerate} 并且需要使用正则表达
我有一个数组a = [1, 2, 3, 4, 5] 如果我在数组中有一个元素,我可以通过a[0].next 有没有一种方法可以用来找到前一个元素a[1].previous 或 a[1].before
是否Enumerable#group_by保留每个值内的原始顺序?当我得到这个时: [1, 2, 3, 4, 5].group_by{|i| i % 2} # => {1=>[1, 3, 5], 0=
我已经基于现有的NativeHashMap.Enumerator和UnSafeHashMap.Enumerator结构编写了枚举数,它们以猝发方式工作,但在尝试为嵌套的非托管结构组合枚举数时遇到了麻烦
在 C# 中使用迭代器创建 Enumerable 或 Enumerator 有什么区别?我知道迭代器用于创建实现 Enumerable 或 Enumerator 的私有(private)类... 哪种
自 C++11 过渡以来,GCC 输出警告“条件表达式中的枚举和非枚举类型”。我想了解此警告背后的原因。比较枚举常量有什么危险? 很明显我们可以通过以下方式摆脱这个警告 -Wno-enum-compa
我在 LINQ 查询的性能方面遇到问题,因此我创建了一个简化的小示例来演示下面的问题。该代码采用一个随机的小整数列表,并返回分成几个较小列表的列表,每个列表总计 10 个或更少。 问题是(正如我所写的
我一直对 Enumerable#all? 和 Enumerable#each 的用例感到困惑。例如 ['.txt', '-hello.txt'].all? do |suffix| pu
Enumerable documentation没有明确说明 each 是 each_entry 的别名,但是 each_entry 的描述与我对 each 1 [1, 2] nil Foo.new.
在这段代码中,我创建了一个字符串数组“1”到“10000”: array_of_strings = (1..10000).collect {|i| String(i)} Ruby Core API 是
我正在为我的代码寻求一些帮助,如下所示: for file in file_name : if os.path.isfile(file): for line_number, l
刚刚下载了 Xcode 7 Beta,此错误出现在 enumerate 关键字上。 for (index, string) in enumerate(mySwiftStringArray) { } 谁
刚刚下载了 Xcode 7 Beta,这个错误出现在 enumerate 关键字上。 for (index, string) in enumerate(mySwiftStringArray) { }
为了清楚起见,假设我们有学生和类(class),这是多对多的关系。 我有一个字典,其中键是学生 ID,而 Enumerable 是一个类的集合(假设我们只有 id ),我想将其恢复为 classId、
我是一名优秀的程序员,十分优秀!