I would like to build the rule for following use case:
Accounts with multiple consecutive deposits (> 10) and immediately after the last deposit (maximum 4 hours later), extraction of the sum of the amount deposited.
For that, I have a Transaction class
public class Transaction
{
private String Id_Event;
private Date Date_Time;
private String Id_Account;
private String Operation_Type;
private Double Amount;
}
I developed this rule, but it doesnt work with sequence events.
rule "Account"
when
$t1:Transaction($id:Id_Account,Operation_Type=="CREDIT")
$t2:Transaction(Id_Account==$id,Operation_Type=="CREDIT",this after $t1)
not (Transaction(Id_Account==$id,Operation_Type=="CREDIT", this after $t1, this before $t2))
not (Transaction(Id_Account==$id,Operation_Type=="CREDIT", this after $t2))
then
......
end
I have the following sequence of events:
T1: A1, Operation_Type: CREDIT, Amount: 100
T2: A1, Operation_Type: CREDIT, Amount: 250
T3: A1, Operation_Type: CREDIT, Amount: 150
T4: A2, Operation_Type: CREDIT, Amount: 800
T5: A1, Operation_Type: CREDIT, Amount: 565
Where T are the transactions and C the accounts. The rule returns as the last, T5, when it should be T3 the last of the consecutive deposits.
Thanks in advance!!!
Related
Hello I have to group by multiple fields and make a summary by one of these files, thereafter I have to work with this result and make some more transformations my problem is that I'm getting a complex structure after the grouping and it's not easy to work with this items. This is my code:
Map<String, Map<String, Map<LocalDateTime, Map<String, Double>>>> processed = null;
processed = itemsToProcess
.stream()
.collect(groupingBy(entity::getId,
groupingBy(entity::getType,
groupingBy(entity::getCreateDate,
groupingBy(entity::getCode,
summingDouble(entity::getPay))))));
The objective of this grouping is the summary of the pays but thereafter I I have to do some transformations with this processed structure, my doubt if is there is a way to transform this in a simple list in order to make more easy this task?
My input is basically a list of:
List<Person> itemsToProcess= new ArrayList<>();
#JsonInclude
public class Person extends Entity<Person > {
private static final long serialVersionUID = 1L;
/* File line content */
private String id;
private String type;
private LocalDateTime createDate;
private String code;
private double pay;
private String city
private String company
}
The output that I'm looking for is the summary of the pay field grouped by {id,type,createDate,pay}
example if I have the next values
Id type createdDAte Code pay more fields....
1 0 today BC 500
1 0 today BC 600
2 0 today BC 600
2 0 today BC 300
3 0 today BC 300
The result must be:
Id type createdDAte Code pay more fields....
1 0 today BC 1100
2 0 today BC 900
3 0 today BC 300
You can use Collectors.toMap to Map by that four properties and merging the same group person objects and creating a new one using the constructor.
List<Person> processed =
new ArrayList<>(
itemsToProcess
.stream()
.collect(Collectors.toMap(
i -> Arrays.asList(i.getId(), i.getType(), i.getCreateDate(), i.getCode()),
i -> i,
(a, b) -> new Person(a.getId(), a.getType(), a.getCreateDate(), a.getCode(),
a.getPay() + b.getPay())))
.values());
Output:
Person [id=2, type=0, createDate=2020-08-18T12:26:15.616034800, code=BC, pay=900.0]
Person [id=3, type=0, createDate=2020-08-18T12:26:15.616034800, code=BC, pay=300.0]
Person [id=1, type=0, createDate=2020-08-18T12:26:15.616034800, code=BC, pay=1100.0]
Demo here
Quick way is to group by a map of the key fields:
groupingBy(e -> Map.<String, Object>of(
"id", e.getId(),
"type", e.getType(),
"createDate", e.getCreateDate(),
"code", e.getCode(),
"pay", e.getPay()
), identity())
Map's equals() method works as you would hope it does.
If I have a list of objects, how do I sort them based on the largest group?
e.g. I read this csv to a list of objects
FirstName, LastName, Age
Michael, Moore, 64
John, Doe, 22
John, Brown, 44
Peter, Piper, 46
John, Johnson, 14
Peter, Rabbit, 5
If I group by FirstName I get
FirstName, Count
Michael, 1
John, 3
Peter, 2
If I sort descending by the count I get
FirstName, Count
John, 3
Peter, 2
Michael, 1
How do I now sort the first list by the order of this sorted group?
FirstName, LastName, Age
John, Doe, 22
John, Brown, 44
John, Johnson, 14
Peter, Piper, 46
Peter, Rabbit, 5
Michael, Moore, 64
So far I have:
val people: List<Person> = readNames(csv)
val group = positions.groupingBy { it.firstName }.eachCount()
val sorted = group.toList().sortedByDescending { (key, value) -> value }
After grouping, the first name has become a key for the importance of that name in the sorted list.
people.sortedByDescending { group[it.firstName] }
You could also sort the list of people by the frequency of first name occurrence, though the operation will be heavier as counting is performed on each item rather than all at once via your grouping.
people.sortedByDescending { person -> people.count { it.firstName == person.firstName } }
Create your eachCount Map which contains each name with related number of occurences. Then sort the original array by the previously determined counts:
val sorted = ps.groupingBy { it.fn }.eachCount().let { counts ->
ps.sortedByDescending { counts[it.fn] }
}
I've got a customer index table that I would like to be able to show the current balance a customer has by comparing the payments made to bills against their total, and then sum up all of the remaining amounts.
At the moment my customer model looks like this (specifically for this question):
public function billToShipments()
{
return $this->hasMany(Shipment::class, 'bill_to');
}
and then my shipment model looks like this (in relation to the payment distributions):
public function paymentDistributions(){
return $this->hasMany('App\Payments_Distribution', 'shipment_id','pro_number');
}
These are the necessary fields related to this specific question:
Under Payment Distributions
-pro_number
-amount (of distribution)
Under Shipments
-balance_due
-bill_to (which is the customer id)
What I'd like to be able to do is get the sum of all balance_due's of bills that have less payment_distributions than the balance due for the customer.
For example, in the shipments (pretend under one customer):
SHIPMENT ID | Balance_Due
1234 | 10.00
1235 | 20.00
1236 | 30.00
and in the payment_distributions table:
PRO_NUMBER | AMOUNT
1234 | 2.00
1234 | 4.00
1235 | 20.00
1236 | 28.00
On the customer I'd like to say that they have a $6.00 balance (because 10.00 minus (2.00 plus 4.00) equals 4.00 for shipment # 1234, $20.00 pays off shipment #1235 completely and 2.00 remains for shipment #1236.
Again, I'd like to use the balance in a table of customers (under an #foreach statement) to give a balance sheet.
---- Updated for Jonas ----
This is how at the moment I grab remaining sums on a one record view for a customer, I pass the following to the view from the controller:
$invoicesOpen = Shipment
::whereRaw('balance > (SELECT IFNULL(SUM(payments_distributions.amount),0) FROM payments_distributions WHERE payments_distributions.shipment_id = pro_number)')
->where('bill_to','=',$customer->id)
->whereNotIn('shipment_billing_status', [2,3])
->orderBy('created_at','desc')->get();
At this point I can see that the customer has $1172.60 remaining, but through Jonas' suggestion, I somehow get -$5477.90
Now there is a closed invoice total that I can get which is currently at $5240.30. This last number is here solely to show that I'm not sure how Jonas' total is calculated.
Add this to your Customer model:
public function getBalanceAttribute() {
$toPay = $this->sum($this->billToShipments->pluck('balance_due'));
$payments = $this->billToShipments->pluck('paymentDistributions')->collapse();
$paid = $this->sum($payments->pluck('amount'));
return bcsub($toPay, $paid, 2);
}
protected function sum($values) {
return $values->reduce(function($carry, $item) {
return bcadd($carry, $item, 2);
}, '0');
}
Then use it like this:
$customers = Customer::with('billToShipments.paymentDistributions')->get();
foreach($customers as $customer) {
// $customer->balance
}
I currently have a table with five columns:
A = Campaign
B = Person
C = Opportunity Name
D = Total Cost of Campaign
E = Date
I'm trying to use COUNTIFS to count the number of rows that match the exact value in cell H2 to column A and has a date range, in column E, that is greater than the value in cell I2.
I have something like this so far:
=countifs($A$2:$A, $H$2, $E$2:$E, ">"&$I$2).
However, I'm having a tough time to trying to dedupe this - it should only count unique rows based on the data in column C, where duplicate names exist. Please refer to my data table as reference:
Campaign Person Opportunity Name Total Cost of Campaign Date
A Bob Airbnb 5000 3/2/2017
B Jim Sony 10000 3/2/2017
B Jane Coca-Cola 10000 3/2/2017
C Jim Sony 200 3/2/2017
B Daniel Sony 10000 3/2/2017
B April Coca-Cola 10000 3/5/2017
For example:
=countifs($A$2:$A, $H$2, $E$2:$E, ">"&$I$2)
with B in H2 and 3/1/2017 in I2 will give me a result of 4 but I'm really trying to extract a value of 2, given that there are only two unique names in Column C (Sony and Coca-Cola).
How could I do this?
You need to include column C in your formula and use COUNTUNIQUE function as #Jeeped have suggested. Here is the final formula that you can use:
=COUNTUNIQUE(IFERROR(FILTER(C:C,A:A=H2,E:E>I2)))
Use COUNTUNIQUE with QUERY
=countunique(QUERY(A:E,"Select C where A = '"&H2&"' and E > date '" & text(I2,"yyyy-mm-dd") & "'",0))
I guess this question is similar to this one:
Selecting fields after grouping in Pig
but here is my question for the following made up sample data:
user_name, movie_name, company, rating
Jim, Jaws, A, 4
Jim, Baseball, B, 4
Matt, Halo, A, 5
Matt, Baseball, B, 4
Matt, History of Chairs, B, 3.5
Pat, History of Chairs, B, 3
John, History of Chairs, B, 2
Frank, Battle Tanks, A, 3
Frank, History of Chairs, B, 5
How can I group together all movies a user has seen without losing the other information like company, and rating.
I want to add the cross of all ratings a user gave from movie company A and movie company B.
Jim, Jaws, Baseball, 8
Matt, Halo, Baseball, 9
Frank, Battle Tanks, History of Chairs, 8
would be the output in the format:
user, companyA, companyB, rating
I started with a load followed by
r1 = LOAD 'data.csv' USING PigStorage(',') as (user_name:chararray, movie_name:chararray, company_name:chararray, rating:int);
r2 = group r1 by user_name;
r3 = foreach r2 generate group as user_name, flatten(r1);
r4A = filter r3 by company_name == 'A';
r4B = filter r3 by company_name == 'B';
but then I have something like
(Frank,Frank,Battle Tanks,A,3)
I then plan to do a cross of r4A and r4B and sum of the ratings. But I'm not sure if the repeated user_name will increase the inefficiencies.
Is this the proper approach? Any ideas to make this better?
Any help would be appreciated!
Can you try this?
input:
Jim,Jaws,A,4
Jim,Baseball,B,4
Matt,Halo,A,5
Matt,Baseball,B,4
Matt,History of Chairs,B,3.5
Pat,History of Chairs,B,3
John,History of Chairs,B,2
Frank,Battle Tanks,A,3
Frank,History of Chairs,B,5
PigScript:
A = LOAD 'input' USING PigStorage(',') AS (user_name:chararray, movie_name:chararray, company:chararray, rating:float);
B = GROUP A BY user_name;
C = FOREACH B {
filterCompanyA = FILTER A BY company=='A';
sumA = SUM(filterCompanyA.rating);
filterCompanyB = FILTER A BY company=='B';
sumB = SUM(filterCompanyB.rating);
GENERATE group AS user,
FLATTEN(REPLACE(BagToString(filterCompanyA.movie_name),'_',',')) AS companyA,
FLATTEN(REPLACE(BagToString(filterCompanyB.movie_name),'_',',')) AS companyB,
(((sumA is null)?0:sumA)+((sumB is null)?0:sumB)) AS Rating;
}
D = FOREACH C GENERATE user,companyA,companyB,Rating;
DUMP D;
Output:
(Jim,Jaws,Baseball,8.0)
(Pat,,History of Chairs,3.0)
(John,,History of Chairs,2.0)
(Matt,Halo,Baseball,History of Chairs,12.5)
(Frank,Battle Tanks,History of Chairs,8.0)
In the above output Pat and John haven't seen any movie in the CompanyA, so that output is null ie empty