Rails, evaluate if numbers are in sequence - arrays

Is there a way to evaluate the order of an array? I want to find an array of records ordered by created_at date and then see if the numbers in that array are in sequence?
For instance:
Model.all.order(&:created_at).select("lesson_number)
[1, 2, 4, 3, 5]
should fail because the numbers are not in sequence
I could execute two finds. One that is ordered by "lesson_number" and one that is ordered by created_at date. Convert them both the a string then compare the two. But, seems like a lot of work if a rails method exists to handle such a thing.

You can combine a couple methods in Ruby to do this pretty efficiently.
input.each_cons(2).reduce(true) { |result, (a, b)| result && (a <=> b) < 0 }
each_cons will iterate through your array yielding, in this case, each 2 consecutive items. Because we don't pass it a block, it returns an enumerator that we can iterate through and get a single resulting value using reduce (a.k.a. inject).
Our block compares a and b using <=> which will return -1, 0, or 1 depending on whether the first value is "less-than", equal, or "greater than". In this case, we want to make sure a is -1.
In case you're not familiar with it, the parenthesis in the block argument are Ruby 1.9+, and they allow the arguments to be splatted in (otherwise we would get a 2-item array in our block).

Related

Sort array based on last digit (as array values are seprated by _ )

my array have is
let arr=['20336.41905.32121.58472_20336.41905.60400.51092_1',
'20336.41905.32121.58472_20336.41905.60400.48025_2',
'20336.41905.32121.58472_20336.41905.41816.60719_3',
'20336.41905.32121.58472_20336.41905.41816.63631_4',
'20336.41905.32121.58472_20336.41905.31747.22942_2',
]
want to get sort as an order like this
['20336.41905.32121.58472_20336.41905.60400.51092_1',
'20336.41905.32121.58472_20336.41905.60400.48025_2',
'20336.41905.32121.58472_20336.41905.31747.22942_2',
'20336.41905.32121.58472_20336.41905.41816.60719_3',
'20336.41905.32121.58472_20336.41905.41816.63631_4',
]
We can try sorting using a lambda expression:
var arr = ['20336.41905.32121.58472_20336.41905.60400.51092_1',
'20336.41905.32121.58472_20336.41905.60400.48025_2',
'20336.41905.32121.58472_20336.41905.41816.60719_3',
'20336.41905.32121.58472_20336.41905.41816.63631_4',
'20336.41905.32121.58472_20336.41905.31747.22942_2',
];
arr.sort((a, b) => parseInt(a.split(/_(?!.*_)/)[1]) - parseInt(b.split(/_(?!.*_)/)[1]));
console.log(arr);
The logic used above is to split on the final underscore of each array value, and parse the right side number to an integer. Then we do a comparison of each pair of numbers to achieve the sort.
Assuming you are using JavaScript...
The sort function can take a callback as an argument. You can use this to determine the criteria by which you desire to sort your array.
When comparing 2 values compare a to b, the function should return a number greater than zero if a goes after b, less than zero if a goes before b, and exactly zero if any could follow the other (ie. 1.10 and 1.100 could be sorted as [1.10, 1.00] or [1.100, 1.00] because for all we care they have the same value, on your particular case, 2 array elements ending in 4 would follow the same principle because that is the only number in our criteria).
An example would be:
arr.sort((a, b)=>{
return parseInt(a.slice(-1)) - parseInt(b.slice(-1))
})
Note that this will only work if the last character on every element of your array is a numeric character and would not ever care about the second to last character if 2 last characters are equal.
There is an ugliest solution too that could work, although I don't really recommend it, it would take into consideration all characters in reverse order.
Map over all elements, reverse them, sort the array without using a callback (arr.sort()), and then reverse all elements again.

How do I use an across loop in post condition to compare an old array and new array at certain indices?

I have a method that shifts all the items, in an array, to the left by one position. In my post condition I need to ensure that my items have shifted to the left by one. I have already compared the first element of the old array to the last element of the new array. How do i across loop through the old array from 2 until count, loop through the new array from 1 until count-1 and compare them? This is my implementation so far.
items_shifted:
old array.deep_twin[1] ~ array[array.count]
and
across 2 |..| (old array.deep_twin.count) as i_twin all
across 1 |..| (array.count-1) as i_orig all
i_twin.item ~ i_orig.item
end
end
end
I expected the result to be true but instead I get a contract violation pointing to this post condition. I have tested the method out manually by printing out the array before and after the method and I get the expected result.
In the postcondition that fails, the loop cursors i_twin and i_orig iterate over sequences 2 .. array.count and 1 .. array.count - 1 respectively, i.e. their items are indexes 2, 3, ... and 1, 2, .... So, the loop performs comparisons 2 ~ 1, 3 ~ 2, etc. (at run-time, it stops on the first inequality). However, you would like to compare elements, not indexes.
One possible solution is shown below:
items_shifted:
across array as c all
c.item =
if c.target_index < array.upper then
(old array.twin) [c.target_index + 1]
else
old array [array.lower]
end
end
The loop checks that all elements are shifted. If the cursor points to the last element, it compares it against the old first element. Otherwise, it tests whether the current element is equal to the old element at the next index.
Cosmetics:
The postcondition does not assume that the array starts at 1, and uses array.lower and array.upper instead.
The postcondition does not perform a deep twin of the original array. This allows for comparing elements using = rather than ~.
Edit: To avoid potential confusion caused by precedence rules, and to highlight that comparison is performed for all items between old and new array, a better variant suggested by Eric Bezault looks like:
items_shifted:
across array as c all
c.item =(old array.twin)
[if c.target_index < array.upper then
c.target_index + 1
else
array.lower
end]
end

Two arrays one with time in, another with time out of something

Lets say we have 2 arrays, one of them (i.e. A) contains the time an object i will come into a room, and the other (i.e. B) contains the time i will leave. Neither of these are in any way sorted and their contents are Real numbers.
For example, object 3 has: A[3]=0.785 and B[3]=4.829.
How would you in O(nlogn) find the max objects in the room at any given time t?
You can try this:
initialize number of objects as zero
sort both arrays
while there are elements left in either array
determine which array's first value is smaller
if the first value in "enter" is smaller, increment number of objects and pop that value
if the first value in "leave" is smaller, decrement number of objects and pop that value
check whether you found a new maximum number of objects
If you can not "pop" elements from the arrays, you can use two index variables instead; also, you will have to add cases for when one of the arrays is already empty.
Sorting has O(nlogn), and the following loop has O(2*n), thus O(nlogn) in total.
Get all times from both arrays and make pairs {time from A or from B; f = +1 for A/ -1 for B}
Sort array of all pairs by time key (in case of tie +1 goes before -1)
Make count = 0
Traverse array of pairs, adding f value to count.
Max value of count is " the max objects in the room"
Example:
A = [2, 5], B = [7, 9]
pairs = (2,1),(5,1),(7,-1),(9,-1)
count = 1, 2, 1, 0
maxcount=2 at interval 5..7

Sort an array so the difference of elements a[i]-a[i+1]<=a[i+1]-a[i+2]

My mind is blown since I began, last week, trying to sort an array of N elements by condition: the difference between 2 elements being always less or equal to the next 2 elements. For example:
Α[4] = { 10, 2, 7, 4}
It is possible to rearrange that array this way:
{2, 7, 10, 4} because (2 - ­7 = ­-5) < (7 - ­10 = -­3) < (10 - ­4 = 6)
{4, 10, 7, 2} because (4 - ­10 = -­6) < (10 - ­7 = ­3) < (7 - ­2 = 5)
One solution I considered was just shuffling the array and checking each time if it agreed with the conditions, an efficient method for a small number of elements, but time consuming or even impossible for a larger number of elements.
Another was trying to move elements around the array with loops, hoping again to meet the requirements, but again this method is very time consuming and also sometimes not possible.
Trying to find an algorithm doesn't seem to have any result but there must be something.
Thank you very much in advance.
I normally don't just provide code, but this question intrigued me, so here's a brute-force solution, that might get you started.
The concept will always be slow because the individual elements in the list to be sorted are not independent of each other, so they cannot be sorted using traditional O(N log N) algorithms. However, the differences can be sorted that way, which simplifies checking for a solution, and permutations could be checked in parallel to speed up the processing.
import os,sys
import itertools
def is_diff_sorted(qa):
diffs = [qa[i] - qa[i+1] for i in range(len(qa)-1)]
for i in range(len(diffs)-1):
if diffs[i] > diffs[i+1]:
return False
return True
a = [2,4,7,10]
#a = [1,4,6,7,20]
a.sort()
for perm in itertools.permutations(a):
if is_diff_sorted(perm):
print "Solution:",str(a)
break
This condition is related to differentiation. The (negative) difference between neighbouring elements has to be steady or increasing with increasing index. Multiply the condition by -1 and you get
a[i+1]-a[i] => a[i+2]-a[i+1]
or
0 => (a[i+2]-a[i+1])- (a[i+1]-a[i])
So the 2nd derivative has to be 0 or negative, which is the same as having the first derivative stay the same or changing downwards, like e.g. portions of the upper half of a circle. That does not means that the first derivative itself has to start out positive or negative, just that it never change upward.
The problem algorithmically is that it can't be a simple sort, since you never compare just 2 elements of the list, you'll have to compare three at a time (i,i+1,i+2).
So the only thing you know apart from random permutations is given in Klas` answer (values first rising if at all, then falling if at all), but his is not a sufficient condition since you can have a positive 2nd derivative in his two sets (rising/falling).
So is there a solution much faster than the random shuffle? I can only think of the following argument (similar to Klas' answer). For a given vector the solution is more likely if you separate the data into a 1st segment that is rising or steady (not falling) and a 2nd that is falling or steady (not rising) and neither is empty. Likely an argument could be made that the two segments should have approximately equal size. The rising segment should have the data that are closer together and the falling segment should contain data that are further apart. So one could start with the mean, and look for data that are close to it, move them to the first set,then look for more widely spaced data and move them to the 2nd set. So a histogram might help.
[4 7 10 2] --> diff [ 3 3 -8] --> 2diff [ 0 -11]
Here is a solution based on backtracking algorithm.
Sort input array in non-increasing order.
Start dividing the array's values into two subsets: put the largest element to both subsets (this would be the "middle" element), then place second largest one into arbitrary subset.
Sequentially put the remaining elements to either subset. If this cannot be done without violating the "difference" condition, use other subset. If both subsets are not acceptable, rollback and change preceding decisions.
Reverse one of the arrays produced on step 3 and concatenate it with other array.
Below is Python implementation (it is not perfect, the worst defect is recursive implementation: while recursion is quite common for backtracking algorithms, this particular algorithm seems to work in linear time, and recursion is not good for very large input arrays).
def is_concave_end(a, x):
return a[-2] - a[-1] <= a[-1] - x
def append_element(sa, halves, labels, which, x):
labels.append(which)
halves[which].append(x)
if len(labels) == len(sa) or split_to_halves(sa, halves, labels):
return True
if which == 1 or not is_concave_end(halves[1], halves[0][-1]):
halves[which].pop()
labels.pop()
return False
labels[-1] = 1
halves[1].append(halves[0][-1])
halves[0].pop()
if split_to_halves(sa, halves, labels):
return True
halves[1].pop()
labels.pop()
def split_to_halves(sa, halves, labels):
x = sa[len(labels)]
if len(halves[0]) < 2 or is_concave_end(halves[0], x):
return append_element(sa, halves, labels, 0, x)
if is_concave_end(halves[1], x):
return append_element(sa, halves, labels, 1, x)
def make_concave(a):
sa = sorted(a, reverse = True)
halves = [[sa[0]], [sa[0], sa[1]]]
labels = [0, 1]
if split_to_halves(sa, halves, labels):
return list(reversed(halves[1][1:])) + halves[0]
print make_concave([10, 2, 7, 4])
It is not easy to produce a good data set to test this algorithm: plain set of random numbers either is too simple for this algorithm or does not have any solutions. Here I tried to generate a set that is "difficult enough" by mixing together two sorted lists, each satisfying the "difference" condition. Still this data set is processed in linear time. And I have no idea how to prepare any data set that would demonstrate more-than-linear time complexity of this algorithm...
Not that since the diffence should be ever-rising, any solution will have element first in rising order and then in falling order. The length of either of the two "suborders" may be 0, so a solution could consist of a strictly rising or strictly falling sequence.
The following algorithm will find any solutions:
Divide the set into two sets, A and B. Empty sets are allowed.
Sort A in rising order and B in falling order.
Concatenate the two sorted sets: AB
Check if you have a solution.
Do this for all possible divisions into A and B.
Expanding on the #roadrunner66 analysis, the solution is to take two smallest elements of the original array, and make them first and last in the target array; take two next smallest elements and make them second and next-to-last; keep going until all the elements are placed into the target. Notice that which one goes to the left, and which one to the right doesn't matter.
Sorting the original array facilitates the process (finding smallest elements becomes trivial), so the time complexity is O(n log n). The space complexity is O(n), because it requires a target array. I don't know off-hand if it is possible to do it in-place.

Finding whether a value is equal to the value of any array element in MATLAB

Can anyone tell me if there is a way (in MATLAB) to check whether a certain value is equal to any of the values stored within another array?
The way I intend to use it is to check whether an element index in one matrix is equal to the values stored in another array (where the stored values are the indices of the elements which meet a certain criteria).
So, if the indices of the elements which meet the criteria are stored in the matrix below:
criteriacheck = [3 5 6 8 20];
Going through the main array (called array) and checking if the index matches:
for i = 1:numel(array)
if i == 'Any value stored in criteriacheck'
%# "Do this"
end
end
Does anyone have an idea of how I might go about this?
The excellent answer previously given by #woodchips applies here as well:
Many ways to do this. ismember is the first that comes to mind, since it is a set membership action you wish to take. Thus
X = primes(20);
ismember([15 17],X)
ans =
0 1
Since 15 is not prime, but 17 is, ismember has done its job well here.
Of course, find (or any) will also work. But these are not vectorized in the sense that ismember was. We can test to see if 15 is in the set represented by X, but to test both of those numbers will take a loop, or successive tests.
~isempty(find(X == 15))
~isempty(find(X == 17))
or,
any(X == 15)
any(X == 17)
Finally, I would point out that tests for exact values are dangerous if the numbers may be true floats. Tests against integer values as I have shown are easy. But tests against floating point numbers should usually employ a tolerance.
tol = 10*eps;
any(abs(X - 3.1415926535897932384) <= tol)
you could use the find command
if (~isempty(find(criteriacheck == i)))
% do something
end
Note: Although this answer doesn't address the question in the title, it does address a more fundamental issue with how you are designing your for loop (the solution of which negates having to do what you are asking in the title). ;)
Based on the for loop you've written, your array criteriacheck appears to be a set of indices into array, and for each of these indexed elements you want to do some computation. If this is so, here's an alternative way for you to design your for loop:
for i = criteriacheck
%# Do something with array(i)
end
This will loop over all the values in criteriacheck, setting i to each subsequent value (i.e. 3, 5, 6, 8, and 20 in your example). This is more compact and efficient than looping over each element of array and checking if the index is in criteriacheck.
NOTE: As Jonas points out, you want to make sure criteriacheck is a row vector for the for loop to function properly. You can form any matrix into a row vector by following it with the (:)' syntax, which reshapes it into a column vector and then transposes it into a row vector:
for i = criteriacheck(:)'
...
The original question "Can anyone tell me if there is a way (in MATLAB) to check whether a certain value is equal to any of the values stored within another array?" can be solved without any loop.
Just use the setdiff function.
I think the INTERSECT function is what you are looking for.
C = intersect(A,B) returns the values common to both A and B. The
values of C are in sorted order.
http://www.mathworks.de/de/help/matlab/ref/intersect.html
The question if i == 'Any value stored in criteriacheck can also be answered this way if you consider i a trivial matrix. However, you are proably better off with any(i==criteriacheck)

Resources