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\$
5
  • \$\begingroup\$ How strict is the IO format? Could A also be a dictionary, or a list of tuples? \$\endgroup\$
    – Laikoni
    Nov 25, 2017 at 14:40
  • \$\begingroup\$ @Laikoni Or even just a list of the form ["A", 2, "B", 3, "C", 5]? \$\endgroup\$ Nov 25, 2017 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, 2017 at 16:16
  • 3
    \$\begingroup\$ What happens if someone tries to overspend, and the intended recipient has already overspent? \$\endgroup\$
    – Nitrodon
    Nov 25, 2017 at 16:19
  • \$\begingroup\$ There's no comma in ["B" 3] in the second and third test cases \$\endgroup\$
    – Jo King
    Nov 26, 2017 at 3:53

5 Answers 5

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\$
2
  • \$\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\$ Nov 25, 2017 at 19:44
  • \$\begingroup\$ @NahuelFouilleul Much better indeed. Thanks! \$\endgroup\$
    – Arnauld
    Nov 25, 2017 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\$
2
  • \$\begingroup\$ 103 bytes \$\endgroup\$
    – ovs
    Nov 25, 2017 at 16:04
  • \$\begingroup\$ @ovs wow, that's clever \$\endgroup\$ Nov 25, 2017 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\$
0
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 and acknowledge that you have read and understand our privacy policy and code of conduct.

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