array_positions() with comparison, not equality - postgresql

Postgres has the function array_positions:
array_positions(ARRAY[1, 4, 3, 1, 3, 4, 2, 1], 1);
-> {1,4,8}
Which checks for equality of the second argument. I can't find anywhere if it has a function for comparison. E.g. (element in array > 1) which would return {2, 3, 5, 6, 7} in this example.
Does postgres have an efficient way of doing this?

SELECT position
FROM UNNEST(ARRAY[1, 4, 3, 1, 3, 4, 2, 1]) WITH ORDINALITY a(element, position)
WHERE element > 1

Related

Postgres width_bucket: function width_bucket(integer, numeric[]) does not exist

I expected results when I run a query passing an array of integers as the second argument to width_bucket such as this:
select width_bucket(5, array[0, 1, 2, 3, 4, 5, 6, 7, 8] )
But if this array contains a decimal number such as this:
select width_bucket( 5, array[0, 1.1, 2, 3, 4, 5, 6, 7, 8] )
I get the error:
ERROR: function width_bucket(integer, numeric[]) does not exist
LINE 1: select width_bucket( 5, array[0, 1.1, 2, 3, 4, 5, 6, 7, 8] )
^
My use case is I'm using this function to calculate my data's breaks, which won't always be integers (and I've seen used elsewhere used with width_bucket in that codebase so I'm not sure why it's not working here).
How can I get width_bucket to accept an array of non-integers?
[Edited to add link to the Postgres docs for the width_bucket function, which says that it accepts "anycompatiblearray" although I don't see where the list of "compatible" array types are defined.]
The error message is misleading here. The issue is not that width_bucket does not support a numeric array, it's that it does not seem to support a mismatch of types between the operand and the thresholds values.
All of these work and return the same value:
select width_bucket( 5.0, array[0, 1.1, 2, 3, 4, 5, 6, 7, 8] )
select width_bucket( 5::numeric, array[0, 1.1, 2, 3, 4, 5, 6, 7, 8] )

Contract m-repeated numbers in list to n-repeated (n<m) in place in O(1) space

I want to write a python 3.7 function that has a sorted list of numbers as an input, and a number n which is the max number each one of the integers can be repeated and modifies the list in place, so that any numbers that are repeated more than n times, would be cut to n repeats, and it should be done in O(1) space, no additional data structures allowed (e.g. set()). Special case - remove duplicates where n = 1. Example:
dup_list = [1, 1, 1, 2, 3, 7, 7, 7, 7, 12]
dedup(dup_list, n = 1)
print(dup_list)
[1, 2, 3, 7, 12]
dup_list = [1, 1, 1, 2, 3, 7, 7, 7, 7, 12]
dedup(dup_list, n = 2)
print(dup_list)
[1, 1, 2, 3, 7, 7, 12]
dup_list = [1, 1, 1, 2, 3, 7, 7, 7, 7, 12]
dedup(dup_list, n = 3)
print(dup_list)
[1, 1, 1, 2, 3, 7, 7, 7, 12]
Case n = 1 is easy, the code is below (code is taken from Elements of Prograqmming Interviews, 2008, page 49 except the last line return dup_list[:write_index]):
def dedup(dup_list):
if not dup_list:
return 0
write_index = 1
for i in range(1, len(dup_list)):
if dup_list[write_index-1] != dup_list[i]:
dup_list[write_index] = dup_list[i]
write_index += 1
return dup_list[:write_index]
This should work:
def dedup2(dup_list, n):
count = 1
list_len = len(dup_list)
i = 1
while i < list_len:
if dup_list[i - 1] != dup_list[i]:
count = 1
else:
count += 1
if count > n:
del(dup_list[i])
i -= 1
list_len -= 1
i += 1
return dup_list
print(dedup2([1, 2, 3, 3, 4, 4, 5, 5, 5, 5, 8, 9], 1))

Can you merge two Flux, without blocking, such that the result only contains unique elements?

Is there a way to merge two Flux such that the result only contains unique elements? I can block on the output and then convert it to a set, but is there a way that does not depend on blocking?
Source (Kotlin)
val set1 = Flux.just(1, 2, 3, 4, 5)
val set2 = Flux.just(2, 4, 6, 8, 10)
val mergedSet = set1.mergeWith(set2)
println(mergedSet.collectList().block())
Output
[1, 2, 3, 4, 5, 2, 4, 6, 8, 10]
Desired Output (order is not important)
[1, 2, 3, 4, 5, 6, 8, 10]
You can use the Flux's merge method and then apply distinct() to it.
Flux.merge (Flux.just(1, 2, 3, 4, 5), Flux.just(2, 4, 6, 8, 10)).distinct();
This way you get a flux which produces only distinct values.

How can I merge 2 observables in a custom fashion?

Custom fashion is:
obs1 = [1, 3, 5, 7, 9], obs2 = [2, 4, 6, 8, 10] -> mergedObs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
I was thinking about obs1.zipWith(obs2) and my bifunction was (a, b) -> Observable.just(a, b) and then it's not trivial for me to flatten Observable<Observable<Integer>>.
That looks like an ordered merge: merge so that the smallest is picked from the sources when they all have items ready:
Flowables.orderedMerge():
Given a fixed number of input sources (which can be self-comparable or given a Comparator) merges them into a single stream by repeatedly picking the smallest one from each source until all of them completes.
Flowables.orderedMerge(Flowable.just(1, 3, 5), Flowable.just(2, 4, 6))
.test()
.assertResult(1, 2, 3, 4, 5, 6);
Edit
If the sources are guaranteed to be the same length, you can also zip them into a structure and then flatten that:
Observable.zip(source1, source2, (a, b) -> Arrays.asList(a, b))
.flatMapIterable(list -> list)
;

Do you have any idea or documentation about why we have arc4random_stir() in swift?

I have written the program below for generating random unique numbers for several number of times by invoking the function, but it seems like I'm getting the same pattern with minimal changes.
func generateRandom(withinNumber: Int) {
var i:Int = 0
var elements = Set<Int>()
while i != withinNumber {
let num:Int = Int(arc4random())%withinNumber + 1
if elements.count <= withinNumber && elements.contains(num) == false {
elements.insert(num)
}
else {
i = i-1
}
i=i+1
}
print(elements)
elements.removeAll()
}
generateRandom(withinNumber: 10)
How does I make my program effectively run to generate several random unique numbers.
Please let me know it would be very helpful for me.
You are storing your numbers in a Set and sets are not ordered, so the order the elements are shown by print is unrelated to the order in which they were added to the set.
Rather the elements of a set are stored in some manner which enables fast checking for .contains(), and this is one reason you seeing similar sequences.
If you wish to preserve order of insertion use a collection which does this, i.e. an array. Changing to an array in your code produced the following results from 9 calls:
[8, 9, 7, 10, 5, 6, 2, 3, 1, 4]
[4, 9, 10, 3, 6, 2, 1, 7, 8, 5]
[8, 3, 5, 1, 6, 4, 9, 10, 7, 2]
[5, 7, 2, 9, 8, 1, 6, 10, 3, 4]
[2, 3, 7, 6, 9, 1, 8, 10, 5, 4]
[9, 10, 2, 4, 6, 8, 5, 7, 1, 3]
[9, 10, 2, 5, 4, 7, 3, 8, 1, 6]
[1, 6, 4, 5, 8, 2, 3, 9, 7, 10]
[6, 10, 5, 3, 2, 8, 1, 9, 7, 4]
You are also generating 10 random numbers in the range 1 to 10 and avoiding duplicates, so the results is always going to be the numbers 1 to 10 in some order.
To generate a random number in a given range do not use %, instead use the provided arc4random_uniform() which will give better a better distribution.
The function mention in your title arc4random_stir() is available in Swift.
BTW (somewhat opinion based): It is better to write !e (! being the boolean not operator) rather than e == false, and never ever write e == true which is the long form of e!
BTW (SO etiquette): Don't link to your code (or paste in images of it). Reduce to a small example which demonstrates the issue (not required in your case) and insert directly in the question. Keep tags minimal and appropriate. These edits were done for you this time by myself and others, you will know for next time.
HTH