How to use arithmetic operator to calculate sum - sanity

I have a review type with a rating field that contains a number from 1 to 5. Now I'd like to calculate the average rating. Relevant schema:
{
name: 'rating',
title: 'Rating',
validation: Rule => Rule.required(),
type: 'number'
},
Sanity recently added arithmetic operations to GROQ, but I'm not sure how to use them and there's very little documentation.
Is it possible to calculate the sum of all ratings using an arithmetic operation? If so, how?
Can you also divide the sum by the number of all reviews in the same query?

I found a solution, quite simple really. You count each star individually and then sum them up and divide them by the total count.
"rating":
(
(count(*[_type=='review' && references(^._id) && rating == 1]) * 1) +
(count(*[_type=='review' && references(^._id) && rating == 2]) * 2) +
(count(*[_type=='review' && references(^._id) && rating == 3]) * 3) +
(count(*[_type=='review' && references(^._id) && rating == 4]) * 4) +
(count(*[_type=='review' && references(^._id) && rating == 5]) * 5)
) / count(*[_type=='review' && references(^._id)])
I'd imagine that this is somewhat expensive for Sanity to calculate, and it's a bit verbose, so I'm still interested in other solutions.

Related

How to do OOP and MVC properly

This afternoon I wrote this but it feels dirty to me. Since I'm learning OOP and MVC, I would like to know if there is a proper way to change nested object's attributes.
For example what is the cleanest way to modify an attribute from an object contained in an object, etc ?
The whole code is here https://github.com/Meezouney/Chess_tournament
If you have any advise, I'll take it :)
Thanks
def enter_match_results(self, nth_round, nth_match):
n_round = self.tournament.get_list_of_rounds()[nth_round]
game = n_round.get_list_of_match()[nth_match]
players = game.get_players()
for i, player in enumerate(players):
if i == 0:
valid_input = 0
while not valid_input:
score = self.view.ask_results(player)
if score == "0" or score == "0,5" or score == "0.5" or score == "1":
if ',' in score:
score = score.replace(',', '.')
valid_input = 1
self.tournament.get_list_of_rounds()[nth_round].get_list_of_match()[nth_match].set_score_player_1(float(score))
else:
self.view.display_score_error()
elif i == 1:
valid_input = 0
while not valid_input:
score = self.view.ask_results(player)
if score == "0" or score == "0,5" or score == "0.5" or score == "1":
if ',' in score:
score = score.replace(',', '.')
valid_input = 1
self.tournament.get_list_of_rounds()[nth_round].get_list_of_match()[nth_match].set_score_player_2(float(score))
else:
self.view.display_score_error()
I am trying to figure out the philosophy of OOP by practicing.

Kotlin aggregate consecutive list elements

I'd like to sum up consecutive numbers in a Kotlin list.
If the list has a 0 then it should start summing up the numbers after 0. The result would be a list of sums. Basically sum up until the first 0 then until the next 0 and so forth.
For example:
val arr = arrayOf(1, 2, 0, 2, 1, 3, 0, 4)
// list of sums = [3, 6, 4]
At the moment I got it working with fold:
val sums: List<Int> = arr.fold(listOf(0)) { sums: List<Int>, n: Int ->
if (n == 0)
sums + n
else
sums.dropLast(1) + (sums.last() + n)
}
but I wonder if there is a simpler or more efficient way of doing this.
I would personally have written it this way:
val sums = mutableListOf(0).also { acc ->
arr.forEach { if (it == 0) acc.add(0) else acc[acc.lastIndex] += it }
}
Using a mutable list, you avoid having to do any drop / concatenation. The code is also easier to follow.
You can still convert it to an immutable list using .toList() if you need to.

Using a While loop and FindRoot

I want to use a While loop and the FindRoot function to estimate a root.
`xroot = FindRoot[x Cos[x] == 0, {x, 2}];
itercnt == 0;
iterlimit == 10000;
While[f[x] > 10^{-5} && itercnt < iterlimit,
x - f[x]/f'[x]; itercnt++]`
I can do it once but I want to do any amount of times. So please give constructive criticism of my code and how it can be simpler.

What is the most efficient way to get a random odd or even number?

So off the top of my head, I can think of a few solutions (focusing on getting random odd numbers for example):
int n;
while (n == 0 || n % 2 == 0) {
n = (arc4random() % 100);
}
eww.. right? Not efficient at all..
int n = arc4random() % 100);
if (n % 2 == 0) n += 1;
But I don't like that it's always going to increase the number if it's not odd.. Maybe that shouldn't matter? Another approach could be to randomize that:
int n = arc4random() % 100);
if (n % 2 == 0) {
if (arc4random() % 2 == 0) {
n += 1;
else {
n -= 1;
}
}
But this feels a little bleah to me.. So I am wondering if there is a better way to do this sort of thing?
Generate a random number and then multiply it by two for even, multiply by two plus 1 for odd.
In general, you want to keep these simple or you run the risk of messing up the distribution of numbers. Take the output of the typical [0...1) random number generator and then use a function to map it to the desired range.
FWIW - It doesn't look like you're skewing the distributions above, except for the third one. Notice that getting 99 is less probable than all the others unless you do your adjustments with a modulus incl. negative numbers. Since..
P(99) = P(first roll = 99) + P(first roll = 100 & second roll = -1) + P(first roll = 98 & second roll = +1)
and P(first roll = 100) = 0
If you want a random set of binary digits followed by a fixed digit, then I'd go with bitwise operations:
odd = arc4random() | 1;
even = arc4random() & ~ 1;

How to optimize code for finding Amicable Pairs

Please see the code I've used to find what I believe are all Amicable Pairs (n, m), n < m, 2 <= n <= 65 million. My code: http://tutoree7.pastebin.com/wKvMAWpT. The found pairs: http://tutoree7.pastebin.com/dpEc0RbZ.
I'm finding that each additional million now takes 24 minutes on my laptop. I'm hoping there are substantial numbers of n that can be filtered out in advance. This comes close, but no cigar: odd n that don't end in '5'. There is only one counterexample pair so far, but that's one too many: (34765731, 36939357). That as a filter would filter out 40% of all n.
I'm hoping for some ideas, not necessarily the Python code for implementing them.
Here is a nice article that summarizes all optimization techniques for finding amicable pairs
with sample C++ code
It finds all amicable numbers up to 10^9 in less than a second.
#include<stdio.h>
#include<stdlib.h>
int sumOfFactors(int );
int main(){
int x, y, start, end;
printf("Enter start of the range:\n");
scanf("%d", &start);
printf("Enter end of the range:\n");
scanf("%d", &end);
for(x = start;x <= end;x++){
for(y=end; y>= start;y--){
if(x == sumOfFactors(y) && y == sumOfFactors(x) && x != y){
printf("The numbers %d and %d are Amicable pair\n", x,y);
}
}
}
return 0;
}
int sumOfFactors(int x){
int sum = 1, i, j;
for(j=2;j <= x/2;j++){
if(x % j == 0)
sum += j;
}
return sum;
}
def findSumOfFactors(n):
sum = 1
for i in range(2, int(n / 2) + 1):
if n % i == 0:
sum += i
return sum
start = int(input())
end = int(input())
for i in range(start, end + 1):
for j in range(end, start + 1, -1):
if i is not j and findSumOfFactors(i) == j and findSumOfFactors(j) == i and j>1:
print(i, j)