12
\$\begingroup\$

Introduction

You have gotten a job as the minister of finance in your made-up country in your back yard. You have decided to make your own bank in your country for you and your less trustworthy friends. Since you don't trust your friends, you have decided to write a program to validate all transactions to stop your friends from overspending your made-up currency and ruining your economy.

Task

Given the starting balance and all transactions, filter out all transactions where someone tries to overspend and block anyone who tries to overspend (this includes trying to overspend to a closed account) from ever using your bank again by filtering out future transactions to or from his/her bank account.

Input/Output

Two lists A and B as input and a list C as output. A is the starting balance of each account with the format [["Alice", 5], ["Bob", 8], ["Charlie", 2], ...]. B is a list of transactions with the format [["Bob", "Alice", 3], ["Charlie", "Bob", 5], ...] where ["Bob", "Alice", 3] means that Bob wants to pay Alice 3 currency units. C should have the same format as B. A, B and C may be in any reasonable format.

Test Cases

A: [["Alice", 5], ["Bob", 2]]
B: [["Alice", "Bob", 5], ["Bob", "Alice" 7]]
C: [["Alice", "Bob", 5], ["Bob", "Alice" 7]]

A: [["A", 2], ["B", 3], ["C", 5]]
B: [["C", "A", 2], ["B", "C", 4], ["A", "B", 2]]
C: [["C", "A", 2]]

A: [["A", 2], ["B", 3]]
B: [["A", "B", 2], ["A", "B", 2]]
C: [["A", "B", 2]]

A: [["A", 4], ["B", 0]]
B: [["A", "B", 1], ["A", "B", 5], ["A", "B", 2]]
C: [["A", "B", 1]]

A: [["A", 2], ["B", 3], ["C", 4]]
B: [["A", "B", 3], ["C", "B", 4]]
C: [["C", "B", 4]]

A: [["A", 2], ["B", 3], ["C", 4]]
B: [["A", "B", 3], ["B", "A", 4], ["C", "B" 2]]
C: []

Scoring

This is , the shortest code in bytes in each language wins.

\$\endgroup\$
  • \$\begingroup\$ How strict is the IO format? Could A also be a dictionary, or a list of tuples? \$\endgroup\$ – Laikoni Nov 25 '17 at 14:40
  • \$\begingroup\$ @Laikoni Or even just a list of the form ["A", 2, "B", 3, "C", 5]? \$\endgroup\$ – Erik the Outgolfer Nov 25 '17 at 14:41
  • \$\begingroup\$ Suggested test case: A: [["A", 2], ["B", 3], ["C", 4]], B: [["A", "B", 3], ["C", "B", 4]], C: [["C", "B", 4]] (a valid transaction following an invalid one). \$\endgroup\$ – Arnauld Nov 25 '17 at 16:16
  • 3
    \$\begingroup\$ What happens if someone tries to overspend, and the intended recipient has already overspent? \$\endgroup\$ – Nitrodon Nov 25 '17 at 16:19
  • \$\begingroup\$ There's no comma in ["B" 3] in the second and third test cases \$\endgroup\$ – Jo King Nov 26 '17 at 3:53
5
\$\begingroup\$

JavaScript (ES6), 91 88 79 bytes

Saved 8 bytes thanks to @NahuelFouilleul

Takes input in currying syntax (a)(b).

a=>b=>b.filter(([x,y,z])=>(a[x]+=z)<0&a[y]<0?a[y]-=z:0,a.map(([x,y])=>a[x]=~y))

Test cases

let f =

a=>b=>b.filter(([x,y,z])=>(a[x]+=z)<0&a[y]<0?a[y]-=z:0,a.map(([x,y])=>a[x]=~y))

console.log(JSON.stringify(f(
  [["Alice", 5], ["Bob", 2]]
)(
  [["Alice", "Bob", 5], ["Bob", "Alice", 7]]
)))

console.log(JSON.stringify(f(
  [["A", 2], ["B", 3], ["C", 5]]
)(
  [["C", "A", 2], ["B", "C", 4], ["A", "B", 2]]
)))

console.log(JSON.stringify(f(
  [["A", 2], ["B", 3]]
)(
  [["A", "B", 2], ["A", "B", 2]]
)))

console.log(JSON.stringify(f(
  [["A", 4], ["B", 0]]
)(
  [["A", "B", 1], ["A", "B", 5], ["A", "B", 2]]
)))

console.log(JSON.stringify(f(
  [["A", 2], ["B", 3], ["C", 4]]
)(
  [["A", "B", 3], ["C", "B", 4]]
)))

Beautified and commented

a => b =>                 // given the two lists a and b
  b.filter(([x, y, z]) => // for each (x = payer, y = payee, z = amount) in b:
    (a[x] += z) < 0 &     //   update the payer's account; if it's still valid
    a[y] < 0 ?            //   and the payee's account is also valid:
      a[y] -= z           //     update the payee's account
    :                     //   else:
      0,                  //     do nothing
    a.map(([x, y]) =>     //   initialization: for each (x = owner, y = amount) in a:
      a[x] = ~y           //     set up this account (>= 0: closed, -1: $0, -2: $1, etc.)
    )                     //   end of map()
  )                       // end of filter()
\$\endgroup\$
  • \$\begingroup\$ what about a=>b=>b.filter(([x,y,z])=>(a[x]-=z)>0&a[y]>0?a[y]+=z:0,a.map(([x,y])=>a[x]=y+1)) porting perl solution to javascript ? \$\endgroup\$ – Nahuel Fouilleul Nov 25 '17 at 19:44
  • \$\begingroup\$ @NahuelFouilleul Much better indeed. Thanks! \$\endgroup\$ – Arnauld Nov 25 '17 at 20:46
4
\$\begingroup\$

Perl 5, 72 + 2 (-ap) = 74 bytes

%h=@F;$_=<>;s/(\S+) (\S+) (\S+)/($h{$1}-=$3)<0||($h{$2}+=$3)<$3?"":$&/ge

try it online

\$\endgroup\$
2
\$\begingroup\$

Python 2, 103 bytes

A,B=input()
C=[]
for i in B:
 N,P,M=i
 if M>A[N]:A[N]=-1
 if A[N]>-1<A[P]:A[N]-=M;A[P]+=M;C+=i,
print C

Try it online!

-12 thanks to ovs.

Longer due to output format restrictions:

C should have the same format as B.

Otherwise I could've done this for 92 bytes:

A,B=input()
for(N,P,M)in B:
 if M>A[N]:A[N]=-1
 if A[N]>-1<A[P]:A[N]-=M;A[P]+=M;print(N,P,M)
\$\endgroup\$
  • \$\begingroup\$ 103 bytes \$\endgroup\$ – ovs Nov 25 '17 at 16:04
  • \$\begingroup\$ @ovs wow, that's clever \$\endgroup\$ – Erik the Outgolfer Nov 25 '17 at 16:09
2
\$\begingroup\$

Ruby, 57 bytes

->a,b{b.select{|(s,r,x)|a[r]+=x if[a[s]-=x,a[r]].min>-1}}

Try it online!

Takes input A as a Hash in the format {"A"=>2, "B"=>3}. Input B and output C are in the suggested format.

Explanation

->a,b{                      # lambda function taking arguments A and B
b.select{|(s,r,x)|              # select items in B that return truthy (s = sender, r = receiver, x = amount)
            a[s]-=x,                # subtract amount from sender
        if [         a[r]].min>-1   # check if the smaller of the balances is non-negative
                                    # (true if both values are non-negative)
a[r]+=x                             # if so, add to the receiver's balance
}                               # the select function returns truthy when the above if statement passes
}
\$\endgroup\$
1
\$\begingroup\$

C++, 193 bytes

Input A as std::map, B as std::list.

#import<bits/stdc++.h>
using s=std::string;struct p{s a,b;int c;};using t=std::list<p>;t f(std::map<s,int>A,t B){t C;for(p&i:B)(A[i.a]-=i.c)<0|A[i.b]<0?0:(C.push_back(i),A[i.b]+=i.c);return C;}

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.