Arrays in Ruby: Take vs Limit vs First - ruby-on-rails

Suppose you have an array of objects in Rails #objects
If I want to display the first 5 objects, what is the difference between using:
#objects.limit(5)
#objects.take(5)
#objects.first(5)
I am talking about the front end (Ruby), NOT SQL. The reason why the objects are not limited in SQL is because the same array may be used elsewhere without applying a limit to it.
Does it have anything to do with object instantiation?

limit is not an array method
take requires an argument; it returns an empty array if the array is empty.
first can be called without an argument; it returns nil if the array is empty and the argument is absent.
Source for 2.0 take
static VALUE
rb_ary_take(VALUE obj, VALUE n)
{
long len = NUM2LONG(n);
if (len < 0) {
rb_raise(rb_eArgError, "attempt to take negative size");
}
return rb_ary_subseq(obj, 0, len);
}
Source for 2.0 first:
static VALUE
rb_ary_first(int argc, VALUE *argv, VALUE ary)
{
if (argc == 0) {
if (RARRAY_LEN(ary) == 0) return Qnil;
return RARRAY_PTR(ary)[0];
}
else {
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST);
}
}
In terms of Rails:
limit(5) will add the scope of limit(5) to an ActiveRecord::Relation. It can not be called on an array, so limit(5).limit(4) will fail.
first(5) will add the scope of limit(5) to an ActiveRecord::Relation. It can also be called on an array so .first(4).first(3) will be the same as .limit(4).first(3).
take(5) will run the query in the current scope, build all the objects and return the first 5. It only works on arrays, so Model.take(5) will not work, though the other two will work.

The answer chosen answer seems to be outdated (in terms of Rails) so I would like to update some information.
limit on an ActiveRecord::Relation will still be a Relation. So if you call:
Model.limit(5).limit(4)
will be same as:
Model.limit(4)
first on an ActiveRecord::Relation will make the result an Array. So you cannot call any scope after first like:
Model.first(5).where(id: 1)
But you can do this:
Model.limit(5).where(id: 1)
take
Model.take(5)
works now. It will return an array, so you cannot call any scope either.
On an ActiveRecord::Relation object, if you call first it will include ORDER BY 'tables'.id. Whereas with limit and take there is no ORDER BY included but the sorting is depended by the database sorting implementation.

Related

Dart Generic Function with Subtype function call

I am not sure if this is even possible but here's my setup:
I have basically 2 Maps holding a special identifier to get some objects.
these identifier is like a versioning number, i may have data in version 8 that belongs to meta version 5. But at the same time, Meta versions up to 10 may exist and not every meta version holds information about every data, so here's where the _filter kicks in.
The filter is able to find to any given value the correct object. So far so good.
My question belongs to the following: (last codeline)
how am i able to say "if you have no matching candidate, generate me a default value"
For this purpose, i tried to force a named constructor with a super class for "Data" and "Meta" called "BasicInformation".
But even if i implement this, how do i call something like T.namedConstructor(); ?
class Repo{
Map<int, Data> mapData;
Map<int, Meta> mapMeta;
Data getData(int value)
{
return _filter<Data>(mapData, value);
}
Meta getMeta(int value)
{
return _filter<Data>(mapMeta, value);
}
T _filter<T extends BasicInformation>(Map<int, T>, int value)
{
//fancy filtering technique
//....
//speudo code
if (found) return map[found]; //speudo code
else return T.generateDefault();
}
}
I've found the following stackoverflow entry: Calling method on generic type Dart
which says, this is not possible without adding a function call.

Dart: How to check if List of Objects is a List of Strings/ints/bools

For simple data types, you can use e.g.
object is String
to check whether an Object variable is of a more specific type.
But let's you have a List, but want to check if it is a List of Strings. Intuitively we might try
List list = ['string', 'other string'];
print(list is List<String>);
which returns false.
Similarly using the List.cast() method doesn't help, it will always succeed and only throw an error later on when using the list.
We could iterate over the entire list and check the type of each individual entry, but I was hoping there might be a better way.
There is no other way. What you have is a List<Object?>/List<dynamic> (because the type is inferred from the variable type, which is a raw List type which gets instantiated to its bound). The list currently only contains String objects, but nothing prevents you from adding a new Object() to it.
So, the object itself doesn't know that it only contains strings, you have to look at each element to check that.
Or, when you create a list, just declare the variable as List<String> list = ...; or var list = ...;, then the object will be a List<String>.
If you are not the one creating the list, it's back to list.every((e) => e is String).
Each element of a List may be of any type BUT IF YOU ARE SURE that all elements have the same type this approach may be useful
bool listElementIs<T>(List l) {
if (l.isEmpty) return true;
try {
if (l[0] is T) return true; // only try to access to check element
} catch (e) {
return false;
}
return false;
}
void main() {
List list = ['string', 'other string'];
print(listElementIs<String>(list)); // prints 'true'
print(listElementIs<int>(list)); // prints 'false'
}
I think a better way to do this is to be specific about your data types.
By specifying the types of variables, you can catch potential errors early on during the development process.
In addition, specifying the types of variables makes the code more readable and understandable.
Furthermore, specifying types can also improve the performance of your code, as the compiler can make certain optimizations based on the types of variables.
List<String> list = <String>['string', 'other string'];
print(list is List<String>); /// prints true.
You can use this linter rule to enforce it:
https://dart-lang.github.io/linter/lints/always_specify_types.html

Overwriting array in dafny

I'm trying to overwrite an array inside a method. The compiler is giving me the error "Error: LHS of assignment must denote a mutable variable".
method invalidSort(a : array<int>)
modifies a;
requires a != null;
ensures sorted(a[..]);
{
a := new int[0];
}
Am I staring myself blind and missing something or why does Dafny not allow this?
In Dafny, method parameters cannot be assigned to. You can use a local variable if you need to update the value internally.
For example,
var a' := new int[0];
If you want this new array to be available to the caller, you'll also need to return it.
return a';
All that said, if you're trying to write an in-place sorting method, then you don't need to do any of this. Just modify a in place.
a[0] := 0;
// ...

Grails Cannot get property 'id' on null object

I am getting this error: Cannot get property 'id' on null object and i can't understand the problem.
Here is my code in provionController.groovy
CreateCriteria returns one element, I verified in the database, size = 1 but when i tried to display the Id, I get this error.
def prov_model = null
def model = Provision_model.CreateCriteria{
gilt_air{
eq("air",air)
}
gilt_coo{
eq("coo",coo)
}
le("date_from", per.begin)
ge("date_to", per.end)
eq("active", 1)
}
println(model.size())
prov_model = model[0]
println(prov_model.id)
but when I am getting it directly by method get(), it hasn't no problem
prov_model = Provision_model.get(57)
println(prov_model.id)
1st: the method is called createCriteria(), not CreateCriteria()
2nd: the method itself DOES NOT invoke any db operation. You have to call list() or get() etc. on it to get the query results
If order to execute the query and store the results in model, replace this
def model = Provision_model.CreateCriteria
with
def model = Provision_model.withCriteria
#injecteer and #Donal both have very valid input. First, you need to address the syntax issue, here is an example of one way to format your criteria:
def prov_model = null
def model = Provision_model.createCriteria().get() {
gilt_air{
eq("air",air)
}
gilt_coo{
eq("coo",coo)
}
le("date_from", per.begin)
ge("date_to", per.end)
eq("active", 1)
}
Keep in mind that by using .get() you are limiting the return from the criteria to one record. Second, if you try writing the criteria both ways, using withCriteria and using the format above and it still doesn't work, your problem may be in the domain model or the configuration of the database.

Magento Varien_Data_Collection returns wrong size after removing items

I'm running on Magento 1.4, but also have verified the problem in 1.7.
Working with an instance of Varien_Data_Collection provides the use of Varien_Data_Collection::removeItemByKey. In my case, I'm removing items from the collection, and later trying to get the updated size of that collection, like so:
$body=$this->getTable()->getBody();
echo $body->getHeight(); // Outputs 25
$body->deleteRow(1);
echo $body->getHeight(); // Still outputs 25
...
My_Model_Body_Class extends Mage_Core_Model_Abstract {
/* #var $_rows Varien_Data_Collection */
protected $_rows;
public function deleteRow($index) {
$this->_rows->removeItemByKey($index);
return $this;
}
public function getHeight() {
return $this->_rows->getSize();
}
}
...
Code limited for brevity.
So if you call my deleteRow method, the item will in fact be removed from the collection, but subsequent calls to get the size of that collection will always return the original count. Therefore, if I have 25 items in the collection, and remove 1, then a call to getSize on the collection returns 25.
I traced this back to the parent class, in Varien_Data_Collection::getSize:
/**
* Retrieve collection all items count
*
* #return int
*/
public function getSize()
{
$this->load();
if (is_null($this->_totalRecords)) {
$this->_totalRecords = count($this->getItems());
}
return intval($this->_totalRecords);
}
We see that the count hinges on the NULL status of the _totalRecords property. So it looks like a bug in core code. Am I reading this correctly? Should I just rely on a call to count on the items?
We see that the count hinges on the NULL status of the _totalRecords
property. So it looks like a bug in core code. Am I reading this
correctly?
Whether to interpret said behaviour as bug or feature, lies in the eyes of the beholder.
This behaviour is not 1.4 specific, btw; it works the same way up to the current CE version (1.8.1).
public function getSize()
{
$this->load();
if (is_null($this->_totalRecords)) {
$this->_totalRecords = count($this->getItems());
}
return intval($this->_totalRecords);
}
Most people for sure expect a method named getSize() to always return the current size, so they may call it a bug, perhaps.
But if you take a closer look at the Varien_Data_Collection class, you'll notice, that getSize() is not the only method that looks somewhat.. "weird".
Take the addItem() and removeItemByKey() methods, for example.
Why don't they increment/decrement the _totalRecords property, when getSize() uses it?
Lazy Loading
The reason for these "weird" behaviours is, that Varien_Data_Collection basically is designed for the usage of the Lazy Loading pattern. That means, it allows to delay loading of the collection, until the data is really needed.
To accomplish this, Varien_Data_Collection implements the IteratorAggregate and Countable interfaces. Their implementation points are the getIterator() and count() methods:
public function getIterator()
{
$this->load();
return new ArrayIterator($this->_items);
}
public function count()
{
$this->load();
return count($this->_items);
}
As you can see, both of these methods call load() first.
The result of this is, that whenever you use foreach or the PHP function count() on the collection, the load() method automatically will be called first.
Now, for a default Varien_Data_Collection nothing special will happen, when load() is called, because load() only calls loadData() and loadData() only returns $this.
But when it comes to its heavily used child class Varien_Data_Collection_Db, then the call to load() will result in loading the collection and setting _totalRecords to the SQL count of loaded records.
For performance reasons the collection usually will be loaded once only (if it hasn't been loaded yet).
So you see, depending on which context you use Varien_Data_Collection in, it perfectly makes sense, why getSize() behaves this way.
Should I just rely on a call to count on the items?
If your collection is not bound to complex or slow I/O, I'd say: yes.
You can simply use:
$n = count($this->_rows->getItems());
Or even this way:
$n = count($this->_rows->getIterator());

Resources