Podio calculations - how to get the source of the entry chosen in a relationship field? - podio

Lets'say I have a relationship field H where the user can choose to add a single entry from any of three different apps (X app, Y app, Z app).
I would like to use this information in a calculation field to calculate results depending on what app the info comes from, rather that the values of the incoming entry.
Is that possible?

If there is always only one related item allowed you can use .length. In this case it counts the number of the related items
var $AppX = #TitleFieldAppX.length;
var $AppX = #TitleFieldAppY.length;
var $AppZ = #TitleFieldAppZ.length;
AppX == 1 ? "Calculate this" : AppY == 1 ? "Calculate that" ? AppZ == 1 : "Calculate else" : null
If an item from App x is related than do this calculation, if from App Y .....

Related

Store targets as collections that handle logic operation

I think my title is kinda unclear but I don't konw how to tell that otherwise.
My problem is:
We have users that belong to groups, there are many types of groups and any user belong to exaclty one group for each type.
Example: With group types A, B and C, containing respectively the groups (A1; A2; A3), (B1; B2) and (C1; C2; C3)
Every User must have a list of groups like [A1, B1, C1] or [A1, B2, C3] but never [A1, A2, B1] or [A1, C2]
We have messages that target to certain groups but not just a union, it can be more complex collection operations
Example: we can have message intended to [A1, B1, C3], [A1, *, *], [A1|A2, *, *] or even like ([A1, B1, C2] | [A2, B2, C1])
(* = any group of the type, | = or)
Messages are stored in a SQL DB, and users can retrieve all messages intended to their groups
How may I store messages and make my Query to reproduce this behavior ?
An option could be to encode both the user groups and the message targets in a (big) integer built on the powers of 2, and then base your query on a bitwise AND between user group code and message target code.
The idea is, group 1 is 1, group 2 is 2, group 3 is 4 and so on.
Level 1:
Assumptions:
you know in advance how many group types you have, and you have very few of them
you don't have more than 64 groups per type (assuming you work with 64-bit integers)
the message has only one target: A1|A2,B..,C... is ok, A*,B...,C... is ok, (A1,B1,C1)|(A2,B2,C2) is not.
Solution:
Encode each user group as the corresponding power of 2
Encode each message target as the sum of the allowed values: if groups 1 and 3 are allowed (A1|A3) the code will be 1+4=5, if all groups are allowed (A*) the code will be 2**64-1
you will have a User table and a Message table, and both will have one field for each group type code
The query will be WHERE (u.g1 & m.g1) * (u.g2 & m.g2) * ... * (u.gN & m.gN) <> 0
Level 2:
Assumptions:
you have some more group types, and/or you don't know in advance how many they are, or how they are composed
you don't have more than 64 groups in total (e.g. 10 for the first type, 12 for the second, ...)
the message still has only one target as above
Solution:
encode each user group and each message target as a single integer, taking care of the offset: if the first type has 10 groups they will be encoded from 1 to 1023 (2**10-1), then if the second type has 12 groups they will go from 1024 (2**10) to 4194304 (2**(10+12)-1), and so on
you will still have a User table and a Message table, and both will have one single field for the cumulative code
you will need to define a function which is able to check the user group vs the message target separately by each range; this can be difficult to do in SQL, and depends on which engine you are using
following is a Python implementation of both the encoding and the check
class IdEncoder:
def __init__(self, sizes):
self.sizes = sizes
self.grouplimits = {}
offset = 0
for i,size in enumerate(sizes):
self.grouplimits[i] = (2**offset, 2**(offset + size)-1)
offset += size
def encode(self, vals):
n = 0
for i, val in enumerate(vals):
if val == '*':
g = self.grouplimits[i][1] - self.grouplimits[i][0] + 1
else:
svals = val.split('|')
g = 0
for sval in svals:
g += 2**(int(sval)-1)
if i > 0:
g *= self.grouplimits[i][0]
print(g)
n += g
return n
def check(self, user, message):
res = False
for i,size in enumerate(self.sizes):
if user%2**size & message%2**size == 0:
break
if i < len(self.sizes)-1:
user >>= size
message >>= size
else:
res = True
return res
c = IdEncoder([10,12,10])
m3 = c.encode(['1|2','*','*'])
u1 = c.encode(['1','1','1'])
c.check(u1,m3)
True
u2=c.encode(['4','1','1'])
c.check(u2,m3)
False
Level 3:
Assumptions:
you adopt one of the above solutions, but you need multiple targets for each message
Solution:
You will need a third table, MessageTarget, containing the target code fields as above and a FK linking to the message
The query will search for all the MessageTarget rows compatible with the User group code(s) and show the related Message data
So you have 3 main tables:
Messages
Users
Groups
You then create 2 relationship tables:
Message-Group
User-Group
If you want to limit users to have access to just "their" messages then you join:
User > User-Group > Message-Group > Message

Define a new column based on preferences in one set of columns, and available resources in another

I have a dataframe with many columns, of which 7 are relevant here.
df1=pd.DataFrame({'Shipment ID':[1,2,3,4,5,6],'Pref 1':['UPS','DHL','DHL','ARA','USPS','FED'],'Pref 2':['DHL','','FED','FED','UPS','USPS'],'Pref 3':['FED','','','DHL','ARA',''],'BudgetUPS':[NaN,'No','Yes',NaN,'No','Yes'],'BudgetUSPS':['Yes','Yes','Yes',NaN,'Yes','No'],'BudgetFED':['No','Yes',NaN,'Yes','Yes','No'],'BudgetARA':['Yes',NaN,NaN,NaN,NaN,'Yes'],'BudgetDHL':['No','Yes','Yes',NaN,'Yes','Yes']})
The data here represents the top 3 customer preferences for a shipping agent for each of the shipments being generated by an e-commerce site. The Budget columns specify whether the budget for the corresponding shipping agent is available, not available, or unknown (due to query failure).
What I need to generate is a column that picks up the top two (or one, or none) of the preferences for each shipment ID and create entries (column name: Prefnbudget) like "FED UPS", "USPS", "DHL ARA", "None" for each shipment. The purpose of this step is to a) detect if a shipment can be processed with customer preference, and the budget constraint (to prevent deadlocks), b) query the customer with a confirmation.
I would like to make the answer as pythonic as possible. It is certainly easy to do this in a loop over a list ['DHL','UPS','USPS','ARA','FED'], etc. but I want something that is more vectorized, and pithily compact.
I copied your dataframe. Below is one way to implement your task:
# this dictionary maps column name to its index (column count) in the dataframe
dictIndexToCol = {col_name: i for i, col_name in enumerate(df1.columns)}
def getPref(row, dictIdxToCol=dictIndexToCol):
""" This function takes the preferences and checks whether Budget value is Yes """
pref1 = row[1]
pref2 = row[2]
pref3 = row[3]
pref_budget = " "
if len(pref1) > 0:
if row[dictIdxToCol[f"Budget{pref1}"]] == "Yes":
pref_budget += pref1 + " "
if len(pref2) > 0:
if row[dictIdxToCol[f"Budget{pref2}"]] == "Yes":
pref_budget += pref2 + " "
if len(pref3) > 0:
if row[dictIdxToCol[f"Budget{pref3}"]] == "Yes":
pref_budget += pref3
return pref_budget
df1["Prefnbudget"] = df1.apply(lambda row: getPref(row), axis=1)

Count items in Infopath field

I created a form in Infopath with a rich text box field. The field is used to keep a list of usernames (first and last). I want to be able to keep a of count each entry and keep a tally. I then want to use that total # of entries to add or subtract from other fields. Is there any way to do that?
Is the rich text box field just a large string? If so you could just use python's built in split function, and either split by ("\r\n"), or (",").
Example:
u = "Bob, Michael, Jean"
x = u.split(",")
X will be a list of usernames. If you are using line breaks for each new username, then replace (",") with ("\r\n").
Now to count the items in a list you just need to iterate on the list you created with a for loop.
Example:
b = 0
u = "Bob, Michael, Jean"
x = u.split(",")
for i in x:
b += 1 // b will be the number of usernames

Conditional Running Tally / Cumulative Sum: Looking for Formula or Script

I work in a warehouse, and I'm using Google Sheets to keep track of inventory. Adding and subtracting is easy, but I've been tasked with creating a "reserve" system:
A number of pieces of stock are reserved for upcoming jobs. When that stock is ordered and received, the reserve quantity is "satisfied" and decreases by the number of pieces received. The problem with setting it up just like the ADD and SUBTRACT function is that not all stock received is "reserved", and my RESERVE totals end up being "-57", "-72", "-112", etc.
I have a large dataset of form responses logged in four columns: Timestamp, Item ID#, Action (ADD, SUBTRACT, or RESERVE), and QTY. What I'm looking for is a way to create a running tally in column E for each unique Item ID#, using the values in column D "QTY". I need for any value <0 to return "0".
Example Sheet
I've been able to create a running tally formula that satisfies my conditions for one Item ID# at a time. To avoid creating a separate column for each Item ID#, though, I need to figure out how to apply it separately to each unique Item ID#, and array it down Column E so each new form response is calculated automatically.
=if(C2="RESERVE",E1+D2,if(and(C2="ADD",(E1+D2)<0),0,E1+D2))
The closest thing to a solution I've been able to find is a script created by user79865 for this question titled: "Running Total In Google Sheets with Array". Unfortunately, trying to plug this into Google Sheets Script Editor gives me an error popup:
TypeError: Cannot read property "length" from undefined. (line 2, file "runningtotal")
I have no programming background and never dreamed I'd be looking at code just to make a running tally.
If anybody can offer any insight into this, fixing or replacing the script or offering an ARRAYFORMULA solution, I'd really appreciate it!
function runningTotal(names, dates, amounts) {
var sum, totals = [], n = names.length;
if (dates.length != n || amounts.length != n) {
return 'Error: need three columns of equal length';
}
for (var i = 0; i < n; i++) {
if (names[i][0]) {
sum = 0;
for (var j = 0; j < n; j++) {
if (names[j][0] == names[i][0] && dates[j][0] <= dates[i][0]) {
sum = sum + amounts[j][0];
}
}
}
else {
sum = '';
}
totals.push([sum]);
}
return totals;
}

Getting a Count of Array Items that Meet a Certain Criteria

I have an array called #friend_comparisons which is populated with a number of user objects. I then sort the array using the following:
#friend_comparisons.sort! { |a,b| b.completions.where(:list_id => #list.id).first.counter <=> a.completions.where(:list_id => #list.id).first.counter }
This is sorting the array by a certain counter associated with each user (the specifics of which are not important to the question).
I want to find out how many user objects in the array have a counter that is greater than a certain number (let's say 5). How do I do this?
Here is how I am currently solving the problem:
#friends_rank = 1
for friend in #friend_comparisons do
if friend.completions.where(:list_id => #list.id).first.counter > #user_restaurants.count
#friends_rank = #friends_rank + 1
end
end
You can use Array#count directly.
#friend_comparisons.count {|friend| friend.counter >= 5 }
Docs: http://ruby-doc.org/core-2.2.0/Array.html#method-i-count
(same for ruby 1.9.3)
Array#select will get the job done.
Docs: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-select
You might do something like this:
number_of_users = #friend_comparisons.select{|friend| friend.counter >= 5 }.size