ruby 数组删除部分数组
数据结构被急切地介绍给新程序员,因为他们在整个职业生涯中都会大量使用它们。 了解它们,它们如何工作,有什么用处,要使用的是可以极大地改变解决方案性能的东西。
正如标题所暗示的那样,在本文上,我将与ruby谈谈数组,并在这儿以及那里详细讨论这种语言如何管理它们。
本文旨在对 基本概念 有 一般理解的 初学者 。
遵循一些示例需要一些Ruby数组知识,例如 添加元素,串联和循环。
数组。 什么,如何和在哪里。
正如语义一词所暗示的 ,数组是对象的连续集合。 该定义在大多数语言中都是字面意义,这意味着存储在所述结构中的对象将顺序放置在内存中,也将按顺序放置在开发人员将在更高级别使用的抽象中。
通常,我们会找到两种不同的“类型”的数组。 静态和动态。 静态数组是我们定义大小的数组,并固定在石头上。 另一方面,动态数组会增大或缩小,通常在我们不知道该结构的最终大小时使用。
检查下一个实现示例(使用C而不是ruby,但请耐心等待)
# include <stdio.h>
int main ()
{
int intArray [ 10 ];
printf ( "Size of int: %ld bytes\n" , sizeof ( int ));
for ( int i= 0 ; i < 10 ; ++i ) {
printf ( "\nElement\t%p" ,&intArray[i]);
}
return 0 ;
}
现在,这段琐碎的代码在执行时将输出非常真实的表示形式, 通常表示计算机编程中的数组是什么。
Size ofint : 4 bytes
Element 0x7ffe9a634b50
Element 0x7ffe9a634b54
Element 0x7ffe9a634b58
Element 0x7ffe9a634b5c
Element 0x7ffe9a634b60
Element 0x7ffe9a634b64
Element 0x7ffe9a634b68
Element 0x7ffe9a634b6c
Element 0x7ffe9a634b70
Element 0x7ffe9a634b74
我们定义了一个 静态 的 整数 数组 。 更具体地说,是一个静态数组, 最多可容纳10个整数。 我们可以看到,每个整数最多将有4个字节的数据,甚至认为我们的数组仍然为空,内存已被保留以备使用。
不仅如此,而且它们的地址特别用这4个字节分隔,这使您对它的工作方式有了一个了解。 您具有第一个存储单元地址,如果从那里开始走了4个字节,则会找到第二个元素。 因此,我们可以假设是这样的:
array [ 4 ]
可以通过从第一个方向开始并向该地址添加4 * [对象大小]来工作,以达到该方向并获取其中的值。
为什么已经预留了内存很重要? 基本上,因为第一个概念“ 内存中的所有内容彼此相邻 ”。 因此,首先需要在内存中找到一个具有[size]个连续可用空间的位置,然后才能开始放置它们。
“ 但是等等,我一直在Ruby中使用.push(element),并且从来没有保留内存的问题 ”。 那是正确的! 那是因为您使用的是动态数组。
动态数组
动态数组是一种特殊的结构,尽管它仍然是数组,但仍然有些复杂,并添加了更多功能,通过使日常数组具有极大的灵活性来使您的生活更轻松。 不用担心,不再使用C。现在,我可以使用Ruby。
让我们从写一些简单的例子开始:
array = []5 .times do
|x| array.push(x)
end
p array
p "First array length: " +array.length().to_s
prefixSumArray = []
array.each do
|x| prefixSumArray.push(x+ 5 )
end
arrayCopy = array
array.concat(arrayCopy.concat(prefixSumArray))
p array
p "First array length after... playing: " +array.length().to_s
好吧好吧 这是很多动作。 让我们分解一下。
array = []
因此,定义一个包含0个元素的新数组,从i = 0到...以及0。
在第一个循环中,我们使用.push方法添加5个元素。 让我们停在那里。 我们知道array.push添加了一个元素,如果该数组没有原始长度,它将使其变大。
现在,在原始大小为0的数组上有1个元素,从该数组保留的内存是一个元素。 对? 好吧,不。 由于我们正在使用动态数组,因此Ruby(通常是其他方法)会为您明确表示数组将具有的每个元素 保留一些额外的空间 。
因此,现在,该数组的内存块将如下所示: [0] []。 再加上一个,将是[0] [1]。 下一步, [0] [1] [2] [] [] []。 至此,您可能已经注意到,当在所有这些push和concat以及添加之后结束新的动态数组时,我们将保留比我们要使用的要多的内存,或者最终要使用的内存。
平均最多浪费O(n)。 但是您毕竟可能会全部使用它!
“ 哦,不!但是我不想浪费空间!他们为什么要那样做 ?” 好问题,基本上只是一种交易。 您将空间复杂度与时间复杂 度进行了交换。 通过使用更多的空间来帮助您,可以使代码更快。 在数组原始范围之外的每一个新元素的推动工作可能会非常昂贵;
至少您将遍历内存,并寻找一个适合阵列的位置。 这涉及到再次查找和保留,以及一些不再使用的内存清理。
考虑到所有这些,每当您使用涉及扩展数组的内置Ruby方法时,实际上是在幕后进行。 因此,单行代码可能不是解决时间紧迫或您必须管理大量数据的问题的最佳方法。
数组和哈希。
我注意到,在学习该主题的过程中,每次获得一个新工具时,都会对它过度使用。 有点像新玩具。 因此,很多人在确实不需要Hash时倾向于使用Hash。 (我去过那里。在那里我看到很多人)。
例如,如果您需要映射{名称:字符串,电话:整数}等对象; 使用0..25,您可以轻松地以...无限的方式解决该问题。 但是,为了进行基准测试,让我们检查一些明显的问题。
# Your code here!
require 'benchmark'
def doByHash
hash_test = Hash.new()
100001 .times { |x|
hash_test[x] = 1000000 +x
}
hash_test
end
def doByPush
array_test = []
100001 .times { |x|
array_test.push(x+ 100000 )
}
array_test
end
def pseudoAlloc
array_test = Array.new( 100001 )
100001 .times { |x|
array_test[x] = x+ 100000
}
array_test
end
Benchmark.bm do |x|
x.report { doByHash }
x.report { doByPush }
x.report { pseudoAlloc }
end
您可以在 此处 运行实现 。 但是我强烈建议您在本地计算机上对其进行基准测试,以便服务器连接不会影响结果。 还要运行几次以获取平均值, 并对要测试的数字有所注意!
对于n = 100k,我得到的平均总时间为:
- 令人惊异的哈希人,具有: 0.026240 #hash
- 您的友好邻居动态数组,该数组最终将自己标识为链接列表: 0.014025 #push数组
- 仍然是动态数组的前卫少年: 0.012692 #带有init(size)的数组
RAW_SINGLE_OUTPUT
user system total real
0.031000 0.000000 0.031000 ( 0.025804)
0.015000 0.000000 0.015000 ( 0.015524)
0.000000 0.000000 0.000000 ( 0.012109)
代码只是在这种特定情况下说明了速度方面的明显表现。 哈希在行为上特别不同,因为理论上每个节点都可以位于内存中的任何位置。 而且,正如我们所看到的,就我的讲座而言,Ruby没有静态数组,即使默认情况下定义了大小,如果不打扰,您将获得的速度差异也不会很大。
请记住,这将随着数据大小而增长。 有时,您将以对时间敏感的代码来处理数据。 降低算法的复杂性是不可能的,因为您已经尽力了。 剩下什么? 硬代码优化。 这个小技巧是我在学习Ruby的过程中遇到的几个技巧之一。
数组的结束语。
静力学的一点点:
总结一下这部分数据。 当我们考虑静态数组时 ,我们拥有“ 不浪费空间 ”的可爱优势。 而且,那太好了! 只有知道您将使用它。 因为一旦定义了该数组, 就 可以了 。 没有删除,没有插入。 不会变大,也不会变小。 除非您将其删除,然后再重新进行一次。
动态方面的 一个 字节 :
当我们使用动态数组时,我们可能会浪费空间和一些时间。 但是您还将获得如此多的灵活性,以至于我确信您会嫉妒编写该源代码的人有很多乐趣。 插入和 删除 ,现在更易于使用。 与他的静态数组兄弟和浪费的空间O(n)相同,索引复杂度也高,这些额外功能的价格是唯一的。
我假设您正在使用Ruby,所以您不会过多考虑前卫的静态数组以及关于内存的所有废话。 但是现在您知道,最后一次push(number)可能会不时地对您的那排无害的阵列造成大量的工作。
结论
在本文中,我们讨论了什么是动态和静态数组。 并快速选择他们在做什么。 现在,请记住,我一直扑在哈希值,在这种特殊的情况。 如果您注意的话,我说了三遍。 ( 这种特殊情况。4 )
哈希值非常有用是有原因的。 当然,这超出了本文的范围,但重点仍然存在。 确保您始终使用锤子以上,否则一切看起来都像钉子!
有关Ruby的更多信息,没有比他们自己更好的资源了。 不要害怕扫一眼每一个功能的源代码,就知道是怎么回事,只是一看还以为......人们谁在那里去,平时不回来。
谢谢您的光临!
翻译自: https://hackernoon.com/arrays-in-ruby-benefits-and-costs-to-use-them-8d143u6j
ruby 数组删除部分数组