Resistors of Unusual Value

23

7

Introduction

When building an electronics project, a schematic may call for a resistor of an unusual value (say, 510 ohms). You check your parts bin and find that you have no 510-ohm resistors. But you do have many common values above and below this value. By combining resistors in parallel and series, you should be able to approximate the 510-ohm resistor fairly well.

Task

You must write a function or program which accepts a list of resistor values (resistors you stock) and a target value (which you aim to approximate). The program must consider:

  • Individual resistors
  • Two resistors in series
  • Two resistors in parallel

The program should compute all possible combinations of 1 and 2 resistors from the stock list (including two copies of the same resistor value), compute their series and parallel resistance, then sort the configurations according to how well they approximate the target value.

The output format should be one configuration per line, with a + denoting series and | denoting parallel, and some space or an = sign before the net resistance.

Formulas

  • The resistance of one resistor is R1
  • The net resistance of two resistors in series is R1 + R2
  • The net resistance of two resistors in parallel is 1 / (1/R1 + 1/R2)
  • The distance between an approximated resistance value and the target value can be calculated as pseudo-logarithmic distance, not linear distance: dist = abs(Rapprox / Rtarget - 1). For example, 200 is closer to 350 than it is to 100.
  • A better distance measure is true logarithmic distance dist = abs(log(Rapprox/Rtarget)), but since this was not specified in the original question, you are free to use either measurement.

Scoring

Score is measured in characters of code, per usual golf rules. Lowest score wins.

Example

We have the following resistors in stock [100, 150, 220, 330, 470, 680, 1000, 1500, 2200, 3300, 4700] and wish to target 510 ohms. The program should output 143 configurations, approximately as shown (you can change the format, but make sure the meaning is easily determined):

680 | 2200     519.444
1000 | 1000    500.
150 + 330      480.
220 + 330      550.
470            470
680 | 1500     467.89
680 | 3300     563.819
100 + 470      570.
220 + 220      440.
100 + 330      430.
470 | 4700     427.273
680 | 4700     594.052
1000 | 1500    600.
470 | 3300     411.406
680 | 1000     404.762
150 + 470      620.
...
many more rows
...
2200 + 4700    6900.
3300 + 4700    8000.
4700 + 4700    9400.

In this example, the best approximation of 510 ohms is given by 680- and 2200-ohm resistors in parallel.

Best of each language so far (1 June 2014):

  1. J - 70 char
  2. APL - 102 char
  3. Mathematica - 122 char
  4. Ruby - 154 char
  5. Javascript - 156 char
  6. Julia - 163 char
  7. Perl - 185 char
  8. Python - 270 char

phosgene

Posted 2014-05-25T23:32:40.753

Reputation: 1 145

Shouldn't it be 253 configurations for the example? 121 in series, 121 in parallel, 11 solitary ones. – Claudiu – 2014-05-26T02:10:08.260

3@Claudiu There is no difference electrically between 100+150 and 150+100; both yield 250 ohms of resistance and consume a 100-ohm resistor and a 150-ohm resistor, so we must not double-count. However, they should be distinguished from 125+125, because although this also yields 250 ohms, it consumes different resistors (which may be preferable, given our part counts). – phosgene – 2014-05-26T02:16:08.820

3

510 is in the E24 series so it's not that unusual to have on hand

– gnibbler – 2014-05-26T05:09:12.573

@gnibbler True, but I'm not about to stock the E24 series across four orders of magnitude. – phosgene – 2014-05-26T05:56:02.823

3Phosgene, what about the R.O.U.V.'s? – unclemeat – 2014-05-26T05:59:11.630

3I don't think they exist. – phosgene – 2014-05-26T06:58:19.780

1We don't usually set deadlines for code golf questions, because it might discourage some people from posting. You can always change accepted answers. – Nzall – 2014-05-26T11:49:23.827

1It's probably too late to change it now, but do note that your distance formula (dist = abs(approx/target - 1)) is not true logarithmic distance (which would, in fact, be given by dist = abs(log(approx/target))). In particular, according to your formula, 50 is a better approximation to 100 (dist = abs(50/100 - 1) = 1/2) than 200 is (dist = abs(200/100 - 1) = 1), whereas by true logarithmic distance they'd be equally good. Also note that your distance formula is not symmetric: 50 is closer to 100 than 100 is to 50. – Ilmari Karonen – 2014-05-26T20:08:53.733

1You have a good point. I will change it anyway, consequences be damned. – phosgene – 2014-05-26T20:33:38.900

Please give exact input and output formats. Should the input be from STDIN or a prompt? – user80551 – 2014-05-27T17:10:16.253

1The formatting is not particularly important, as long as it's easy to enter/read. The code is meant to assist with building electronics. – phosgene – 2014-05-27T17:23:01.670

Answers

6

J - 86 71 70 char

((]/:[|@<:@%~2{::"1])(;a:,<)"0,[:,/(<,.+`|,.+/;+&.%/)"1@;@((<@,.{:)\))

I'm not going to bother to explain every little detail because a lot of the code is spent syncing up the results of different functions, but here's the gist of the golf:

  • ;@((<@,.{:)\) makes every possible pair of resistors, to be connected either in parallel or in series.

  • [:,/(<,.+`|,.+/;+&.%/)"1@ then connects them, in parallel and in series, making a big list of possible connections.

  • (;a:,<)"0, adds in the possibility of using only one resistor by itself to approximate.

  • (]/:[|@<:@%~2{::"1]) sorts the list of combinations of resistors by the pseudolog distance (|@<:@%) between the target and the resultant resistance from each combination.

And this is how to use it:

   rouv =: ((]/:[|@<:@%~2{::"1])(;a:,<)"0,[:,/(<,.+`|,.+/;+&.%/)"1@;@((<@,.{:)\))
   # 510 rouv 100 150 220 330 470 680 1000 1500 2200 3300 4700      NB. how many?
143
   10 {. 510 rouv 100 150 220 330 470 680 1000 1500 2200 3300 4700  NB. view first 10
+---------+-+-------+
|680 2200 |||519.444|
+---------+-+-------+
|1000 1000|||500    |
+---------+-+-------+
|150 330  |+|480    |
+---------+-+-------+
|220 330  |+|550    |
+---------+-+-------+
|470      | |470    |
+---------+-+-------+
|680 1500 |||467.89 |
+---------+-+-------+
|680 3300 |||563.819|
+---------+-+-------+
|100 470  |+|570    |
+---------+-+-------+
|220 220  |+|440    |
+---------+-+-------+
|100 330  |+|430    |
+---------+-+-------+

You don't have to only view the first 10 like I did above, but this is a function and the J REPL truncates very large return values, and the full output for this example has 287 lines. You can force it all to STDOUT with something like tmoutput toCRLF , LF ,.~ ": blah rouv blah on Windows—drop the toCRLF on Linux—but rouv is a function and internally, all the rows exist.

Note:

The question seems to have been changed right under our noses, and now the log distance is defined as abs(log(Rapprox/Rtarget)) instead of abs(Rapprox/Rtarget-1). To correct this in my golf, we can change the |@<:@% to |@^.@%: <: is Decrement while ^. is Logarithm.

algorithmshark

Posted 2014-05-25T23:32:40.753

Reputation: 8 144

Though your code is seemingly unfathomable, we can still appreciate the mystery. Best score after one day - will it stand? – phosgene – 2014-05-26T20:27:39.293

1No, I do not want to send a mail to -.&a:@,@:{@(({.; – Kilazur – 2014-05-27T12:31:27.307

12

Mathematica, 151 122 characters

Expects the target resistance to be stored in r and the list of available resistors in l.

SortBy[Join[{#,#}&/@l,Join@@(#@@@Union[Sort/@N@l~Tuples~{2}]&/@{{"+",##,#+#2}&,{"|",##,#*#2/(#+#2)}&})],Abs[#[[-1]]/r-1]&]

Less golf:

SortBy[Join[{#, #} & /@ l,
  Join @@ (# @@@ 
       Union[Sort /@ N@l~Tuples~{2}] & /@ {{"+", ##, # + #2} &, {"|", ##, 
        #*#2/(# + #2)} &})], Abs[#[[-1]]/r - 1] &]

The output format differs from the suggested one but configurations are easily determinable. The output is a list of configurations. Each configuration is of one of the following forms:

{R1, Total}
{"+", R1, R2, Total}
{"|", R1, R2, Total}

So the first three elements of the output read

{{"|", 680., 2200., 519.444}, {"|", 1000., 1000., 500.}, {"+", 150., 330., 480.}, ...}

If you're fine with rational numbers, I could save two characters from omitting N@. That is, the first element (for instance) would be returned as 4675/9 instead of 519.444.

Martin Ender

Posted 2014-05-25T23:32:40.753

Reputation: 184 808

Nice work. You beat me to it (and with shorter code). – DavidC – 2014-05-26T00:34:03.000

15Didn'# your den#is# w@rn you @g@ins# e@#ing #h@# much syn#@c#ic sug@r? – phosgene – 2014-05-26T01:36:13.923

2@N@l Tuples? Is that some sort of programmers' disease? – clabacchio – 2014-05-27T14:46:47.390

@clabacchio amazing, I didn't even see that. phosgene, he must have forgotten to mention it... or maybe he just likes to play golf, too... – Martin Ender – 2014-05-27T14:50:02.050

10

APL (102)

{V←{⊃¨⍺{⍺,⍺⍺,⍵,'=',⍺⍵⍵⍵}⍺⍺/¨Z/⍨≤/¨Z←,∘.,⍨⍵}⋄K[⍋|¯1+⍺÷⍨0 4↓K←↑('|'{÷+/÷⍺⍵}V⍵),('+'+V⍵),{⍵,'  =',⍵}¨⍵;]}

This takes the target resistance as the left argument and a list of available resistors as the right argument.

Explanation:

  • V←{...}: V is a function that:
    • Z/⍨≤/¨Z←,∘.,⍨⍵: finds every unique combination of two values in ,
      • Z←,∘.,⍨⍵: join each value in with each value in , store in Z,
      • Z/⍨≤/¨Z: select from Z those combinations where the first value is less than or equal to the second value
    • ⍺{...}⍺⍺/¨: and then applies following function, bound with the left function (⍺⍺) on the right and the left argument () on the left, to each pair:
      • ⍺,⍺⍺,⍵,'=',⍺⍵⍵⍵, the left argument, followed by the left bound argument, followed by the right argument, followed by =, followed by the right function (⍵⍵) applied to both arguments. (This is the formatting function, X [configuration] Y [equals] (X [fn] Y).)
    • ⊃¨: and then unbox each element.
  • {⍵,' =',⍵}¨⍵: for each element in , make the configurations for the individual resistors. (, nothing, nothing, =, ).
  • ('+'+V⍵): use the V function to make all serial configurations (character is '+' and function is +).
  • '|'{÷+/÷⍺⍵}V⍵: use the V function to make all parallel configurations (character is '|' and function is {÷+/÷⍺⍵}, inverse of sum of inverse of arguments).
  • K←↑: make this into a matrix and store it in K.
  • 0 4↓K: drop the 4 first columns from K, leaving only the resistance values.
  • |¯1+⍺÷⍨: calculate the distance between and each configuration.
  • K[⍋...;]: sort K by the distances.

marinus

Posted 2014-05-25T23:32:40.753

Reputation: 30 224

3I'll take your word that it works. My keyboard is missing rather a lot of these characters :D – phosgene – 2014-05-26T01:16:31.893

@phosgene: If you want to test it, you can download a trial version of Dyalog APL at dyalog.com. Then just paste the whole thing in, it should work. The arguments go on the sides, so for example: 510 code_here 100, 150, 220, 330, 470, 680, 1000, 1500, 2200, 3300, 4700 – marinus – 2014-05-26T01:19:41.103

@phosgene You can try this online interpreter, though it doesn't provide the complete output you can verify that the starting few lines and the last few lines are the same.

– user12205 – 2014-05-26T22:32:50.050

Verified! APL is some esoteric stuff. – phosgene – 2014-05-26T22:54:25.320

1@ace TryAPL is very limited, and usually it does not work. That it happens to work on this one is merely a coincidence. It doesn't support eval (), I/O (), or any system variables (even ⎕UCS and ⎕A don't work) so most APL programs will not run. It will actually give a SYNTAX ERROR if one of the disabled functions is used. The fact that this one happens not to use one of the many functions that TryAPL doesn't support, is a coincidence. – marinus – 2014-05-27T00:08:14.343

4

Python 3 - 250 247 270 bytes

from itertools import*
import sys
r=sys.argv[1:]
t=int(r.pop())
p=set(map(tuple,map(sorted,product(r,r))))
a=[('+'.join(b),sum(map(int,b)))for b in p]+[('|'.join(b),1/sum(map(lambda n:1/int(n),b)))for b in p]
for s in sorted(a,key=lambda b:abs(float(b[1])/t-1)):print(s)

Run like this:

python resistors.py 100 150 220 330 470 680 1000 1500 2200 3300 4700 510

(that is, a space-delimited list of resistors, with the target value at the end)

Output:

('2200|680', 519.4444444444445)
('1000|1000', 500.0)
('150+330', 480)
('220+330', 550)
('1500|680', 467.88990825688074)
('3300|680', 563.8190954773869)

[snip]

('2200+4700', 6900)
('3300+4700', 8000)
('4700+4700', 9400)

I would say that outputting, say, 680|2200 and 2200|680 separately is still pretty clear. If this is unacceptable, I can change it, but it'll cost me bytes. Wasn't acceptable. Cost me bytes. Now I sort the tuples before chucking them into the set, otherwise the solution is identical.

undergroundmonorail

Posted 2014-05-25T23:32:40.753

Reputation: 5 897

Sure, output looks plenty clear to me! – phosgene – 2014-05-26T01:38:23.677

However, you are double-counting things. 150+330 is electrically identical to 330+150, so only one of them should appear in the result (143 total configurations for the example). – phosgene – 2014-05-26T02:04:37.260

@pho Okay, fixed. A few extra bytes but the solution should be valid now. – undergroundmonorail – 2014-05-26T04:49:51.863

Also I think your program doesn't look for a single resistor, at all (a+=[(a,a)for a in r]). You can skip a=... as you use a exactly one time. About this import sys;r=sys.args[1:], use r=input().split() and say that you have to give the values on stdin. At last: you use 1/sum(1/int(n)for n in b) instead of 1/sum(map(lambda n:1/int(n),b). All in all, that should be 274 chars – WorldSEnder – 2014-05-26T16:35:20.860

I just golfed 1 more char: Use print(*sorted(...),sep='\n') – WorldSEnder – 2014-05-26T16:41:25.180

3

Ruby 2.1, 156 154 bytes

s=->(a,z){c={};a.map{|e|a.map{|f|c[e]=e;c[e+f]="#{e}+#{f}";c[1/(1.0/f+1.0/e)]="#{e}|#{f}"}};c.sort_by{|k,|(k/z.to_f-1).abs}.map{|e|puts"#{e[1]}=#{e[0]}"}}

Ungolfed:

s =->(a,z) {
  c={}
  a.map{|e|
    a.map{|f|
      c[e]=e
      c[e+f]="#{e}+#{f}"
      c[1/(1.0/f+1.0/e)]="#{e}|#{f}"
    }
  }
  c.sort_by{|k,|
    (k/z.to_f-1).abs
  }.map{|e|
    puts "#{e[1]}=#{e[0]}"
  }
}

What it does:

  • For each value e in a;
    • Iterate through a, computing single, series, and parallel values as keys to printed values in hash c;
  • Determine distance from z for each key in c; and,
  • For each value e[1] for each key e[0] in c, print e[1]=e[0].

Sample usage:

s[[100, 150, 220, 330, 470, 680, 1000, 1500, 2200, 3300, 4700], 510]

Sample output:

2200|680=519.4444444444445
1000|1000=500.0
330+150=480
330+220=550
470=470
1500|680=467.88990825688074
3300|680=563.8190954773869
.
.
.
4700+1500=6200
3300+3300=6600
4700+2200=6900
4700+3300=8000
4700+4700=9400

josh

Posted 2014-05-25T23:32:40.753

Reputation: 131

3

JavaScript (ECMAScript 6) - 186 Characters

f=(R,T)=>(D=x=>Math.abs(x[3]/T-1),r={p:(x,y)=>x*y/(x+y),s:(x,y)=>x+y},[...[[x,0,0,x]for(x of R)],...[[x,y,z,r[z](x,y)]for(x of R)for(y of R)for(z in r)if(x<=y)]].sort((a,b)=>D(a)-D(b)))

Input:

  • An array R of resistor strengths; and
  • T, the target resistance.

Output:

An array of arrays (sorted by distance from T) each containing:

  • the smaller resistor's value;
  • the higher resistor's value (or 0 if a solitary resistor);
  • p, s or 0 if the resistors are in parallel, serial or solitary; and
  • the net resistance.

Explanation:

f=(R,T)=>(                               // Create a function f with arguments R & T
  D=x=>Math.abs(x[3]/T-1),               // A function D to calculate relative
                                         // distance from the target value
  r={p:(x,y)=>x*y/(x+y),s:(x,y)=>x+y},   // An object containing the formulae
                                         // to calculate resistance in serial and parallel
  solitary = [[x,0,0,x]for(x of R)],     // Create an array of solitary resistors
  pairs =                                // Use Array Comprehension to create the array of
   [[x,y,z,r[z](x,y)]                    // arrays
      for(x of R)                        // for each resistor value
      for(y of R)                        // for each resistor value (again)
      for(z in r)                        // for both serial & parallel
      if(x<=y)],                         // where the first resistor value is smaller than the second
  [
    ...solitary,                         // Use the spread ... operator to combine
    ...pairs                             // the two arrays
  ]
    .sort((a,b)=>D(a)-D(b))              // Sort the arrays by minimum distance
                                         // and return.
)

MT0

Posted 2014-05-25T23:32:40.753

Reputation: 3 373

Single resistor missing (output len for example input is 132 instead of 143). I'd like to borrow the Array Comprehension trick, if I just could understand it... – edc65 – 2014-05-26T13:16:05.060

Ah, forgot the solitary resistors – MT0 – 2014-05-26T14:28:53.073

3

Julia - 179 163 bytes

f(t,s)=(\ =repmat;m=endof(s);A=A[v=(A=s\m).>=(B=sort(A))];B=B[v];F=[s,C=A+B,A.*B./C];n=sum(v);print([[s P=[" "]\m P;A [+]\n B;A [|]\n B] F][sortperm(abs(F-t)),:]))

This works the same as the old version, but the argument in the print statement has been organised slightly differently to reduce the number of square brackets necessary. Saves 4 bytes. Absorbing the spaces vector creation into the print argument saves an extra 2 bytes. It has also switched from using "find" to get the relevant indices to using the logical form. Saves 6 bytes. Absorbing the calculation of the index vector into the adjustment of A saved another 2 bytes. Finally, replacing endof(v) with sum(v) saved 2 more bytes. Total saving: 16 bytes.

Old version:

f(t,s)=(\ =repmat;m=endof(s);A=s\m;v=find(A.>=(B=sort(A)));A=A[v];B=B[v];F=[s,C=A+B,A.*B./C];n=endof(v);P=[" "]\m;print([[s,A,A] [P,[+]\n,[|]\n] [P,B,B] F][sortperm(abs(F-t)),:]))

Within the function, here's what it's doing:

\ =repmat            # Overloads \ operator to save lots of characters
m=endof(s)           # Length of input s ("Stock")
A=s\m                # Equivalent to repmat(s,m) (see first command)
B=sort(A)            # Same as A but sorted - rather than cycling through
                     # the resistors m times, it repeats each one m times
v=find(A.>=B)        # Identify which pairs for A,B have A>=B
A=A[v];B=B[v]        # Remove pairs where A<B (prevents duplicates)
F=[s,C=A+B,A.*B./C]  # Constructs vector containing results for single resistor,
                     # resistors in series, and resistors in parallel
n=endof(v)           # equivalent to n=(m+1)m/2, gets number of relevant pairs
P=[" "]\m            # Construct array of blank entries for use in constructing output
print([[s,A,A] [P,[+]\n,[|]\n] [P,B,B] F][sortperm(abs(F-t)),:]))
# The following are the components of the argument in the print statement:
[s,A,A]              # Set of resistor values for resistor 1
[P,[+]\n,[|]\n]      # Operator column, prints either nothing, +, or |
[P,B,B]              # Set of resistor values for resistor 2 (blank for single resistor)
F                    # Contains resulting equivalent resistance
[sortperm(abs(F-t)),:] # Determines permutation for sorting array by distance from Target t
                     # and applies it to array

Sample output:

julia> f(170,[100,220,300])
300  |  300  150
100  +  100  200
300  |  220  126.92307692307692
220          220
220  |  220  110
100          100
300  |  100  75
220  |  100  68.75
100  |  100  50
300          300
220  +  100  320
300  +  100  400
220  +  220  440
300  +  220  520
300  +  300  600

Glen O

Posted 2014-05-25T23:32:40.753

Reputation: 2 548

Nice! Don't see many Julia submissions - is it growing in popularity? – phosgene – 2014-05-26T18:17:59.673

@phosgene - I hope it is; I'm mostly submitting these because they're giving me extra experience with the language. – Glen O – 2014-05-26T18:24:20.963

2

Javascript (E6) 156 162 164 186

Last Edit Assuming all resistor values > 0, you can use them for the loop condition

F=(t,s)=>{D=a=>Math.abs(a[1]/t-1);for(i=r=[];a=s[j=i++];r[l]=[a,a])for(;b=s[j--];)l=r.push([a+'+'+b,c=a+b],[a+'|'+b,a*b/c]);return r.sort((a,b)=>D(a)-D(b))}

Usage : F(510, [100, 150, 220, 330, 470, 680, 1000, 1500, 2200, 3300, 4700])

Ungolfed

F = (t,s) => 
{
  D = a => Math.abs(a[1]/t-1);
  for (i=r=[]; a=s[j=i++]; r[l]=[a,a])
    for(; b=s[j--];)
      l = r.push([a+'+'+b, c=a+b], [a+'|'+b, a*b/c]);
   return r.sort((a,b) => D(a)-D(b))
}

edc65

Posted 2014-05-25T23:32:40.753

Reputation: 31 086

1Must push(score,lower)! – phosgene – 2014-05-26T20:25:43.560

Last I checked, all of my resistors were positively-valued. I think it's a safe assumption. – phosgene – 2014-05-28T03:21:43.440

1

Javascript, 248 bytes

function r(T,L){R=[],O="";for(i in L){R.push([a=L[i],a]);for(j=i;j<L.length;)b=L[j++],s=a+b,R.push([a+"+"+b,s],[a+"|"+b,a*b/s])}R.sort(function(a,b){A=Math.abs;return A(a[1]/T-1)-A(b[1]/T-1)});for(i in R)q=R[i],O+=q[0]+"="+q[1]+"\n";console.log(O)}

Usage : r(510, [100, 150, 220, 330, 470, 680, 1000, 1500, 2200, 3300, 4700]);

Output

670|2200=519.4444444444445
1000|1000=500
150+330=480

(...such rows...)

2200+4700=6900
3300+4700=8000
4700+4700=9400

Snack

Posted 2014-05-25T23:32:40.753

Reputation: 2 142

0

Perl, 213 199 185 bytes

213 bytes:

$t=pop;sub t{abs 1-(split/=/,pop)[1]/$t}sub S{$_[0]+$_[1]}sub P{$_[0]*$_[1]/&S}$"=',';@i=@ARGV;say for sort{t($a)<=>t($b)}grep s!(..\b(\d+)\b,?\b(\d+)?\b\))=\K(??{$2<$3})!$1!ee&&/\d$/,<{S,P}({@i},{@i})= S({@i})=>;

199 bytes:

$t=pop;sub t{abs 1-(split/=/,pop)[1]/$t}sub S{$_[0]+$_[1]}sub P{$_[0]*$_[1]/&S}$"=',';@i=@ARGV;say for sort{t($a)<=>t($b)}grep/(..(\d+),?(\d+)?\))/&&$2>=$3&&($_.=eval$1),<{S,P}({@i},{@i})= S({@i})=>;

185 bytes:

$t=pop;sub t{abs 1-$_[0]=~s!.*=!!r/$t}sub S{$_[0]+$_[1]}sub P{$_[0]*$_[1]/&S}$"=',';$i="{@ARGV}";say for sort{t($a)<=>t$b}grep{my($x,$y)=/\d+/g;$_.='='.eval,$x>=$y}<{S,P}($i,$i) S($i)>

Pass all available resistors as arguments. The target resistance should be the last:

$ perl -E 'code' R1 R2 R3 ... Rn target

How it works (old code)

  • Define subroutines S and P to compute the sum and parallel values of two resistors.

  • Set $" to "," to interpolate @ARGV inside the glob operator

  • <{S,P}({@i},{@i})= S({@i})=> generates a cartesian of all possibilities:

    S(100,100), S(100,150), S(100,220), ... P(100,100), P(100,150) ... S(100), S(150) ...

  • Combine s///ee with grep to evaluate the equivalent resistances and filter out unwanted repeats (performed by (??{$2<$3}) and /\d$/

  • sort by fitness computed in subroutine t

Changes in new code

  • Avoid use of s///ee, use shorter regex with conditional checking and eval inside grep

  • Replace repeats of "{@i}" with$i`

  • Introduce $x, $y instead of $2, $3

  • Replace split/=/,pop with $_[0]=~s!!!r

  • No need for trailing ;

  • eval; is equivalent to eval $_;

  • Add = along with eval-ed answer instead of declaring it up front

Output:

P represents resistors in parallel, S represents resistors in series.

P(2200,680)=519.444444444444
P(1000,1000)=500
S(330,150)=480
S(330,220)=550
S(470)=470
P(1500,680)=467.889908256881
P(3300,680)=563.819095477387
S(470,100)=570
S(220,220)=440
S(330,100)=430
P(4700,470)=427.272727272727
P(4700,680)=594.052044609665
P(1500,1000)=600
P(3300,470)=411.405835543767
P(1000,680)=404.761904761905
S(470,150)=620
P(2200,470)=387.265917602996
S(220,150)=370
S(330,330)=660
P(1500,470)=357.868020304569
S(680)=680
P(680,680)=340
P(2200,1000)=687.5
S(330)=330
S(470,220)=690
S(220,100)=320
P(1000,470)=319.727891156463
P(4700,330)=308.349900596421
S(150,150)=300
P(3300,330)=300
P(2200,330)=286.95652173913
P(680,470)=277.913043478261
P(1500,330)=270.491803278689
P(1500,1500)=750
P(3300,1000)=767.441860465116
S(150,100)=250
P(1000,330)=248.12030075188
S(680,100)=780
P(470,470)=235
P(680,330)=222.178217821782
S(470,330)=800
S(220)=220
P(4700,220)=210.162601626016
P(3300,220)=206.25
S(100,100)=200
P(2200,220)=200
P(4700,1000)=824.561403508772
P(470,330)=193.875
P(1500,220)=191.860465116279
S(680,150)=830
P(1000,220)=180.327868852459
P(680,220)=166.222222222222
P(330,330)=165
S(150)=150
P(470,220)=149.855072463768
P(4700,150)=145.360824742268
P(3300,150)=143.478260869565
P(2200,150)=140.425531914894
P(1500,150)=136.363636363636
P(330,220)=132
P(1000,150)=130.434782608696
P(2200,1500)=891.891891891892
P(680,150)=122.89156626506
S(680,220)=900
P(470,150)=113.709677419355
P(220,220)=110
P(330,150)=103.125
S(100)=100
P(4700,100)=97.9166666666667
P(3300,100)=97.0588235294118
P(2200,100)=95.6521739130435
P(1500,100)=93.75
P(1000,100)=90.9090909090909
P(220,150)=89.1891891891892
P(680,100)=87.1794871794872
P(470,100)=82.4561403508772
S(470,470)=940
P(330,100)=76.7441860465116
P(150,150)=75
P(220,100)=68.75
P(150,100)=60
P(100,100)=50
S(1000)=1000
S(680,330)=1010
P(3300,1500)=1031.25
S(1000,100)=1100
P(2200,2200)=1100
P(4700,1500)=1137.09677419355
S(680,470)=1150
S(1000,150)=1150
S(1000,220)=1220
P(3300,2200)=1320
S(1000,330)=1330
S(680,680)=1360
S(1000,470)=1470
P(4700,2200)=1498.55072463768
S(1500)=1500
S(1500,100)=1600
S(1500,150)=1650
P(3300,3300)=1650
S(1000,680)=1680
S(1500,220)=1720
S(1500,330)=1830
P(4700,3300)=1938.75
S(1500,470)=1970
S(1000,1000)=2000
S(1500,680)=2180
S(2200)=2200
S(2200,100)=2300
S(2200,150)=2350
P(4700,4700)=2350
S(2200,220)=2420
S(1500,1000)=2500
S(2200,330)=2530
S(2200,470)=2670
S(2200,680)=2880
S(1500,1500)=3000
S(2200,1000)=3200
S(3300)=3300
S(3300,100)=3400
S(3300,150)=3450
S(3300,220)=3520
S(3300,330)=3630
S(2200,1500)=3700
S(3300,470)=3770
S(3300,680)=3980
S(3300,1000)=4300
S(2200,2200)=4400
S(4700)=4700
S(3300,1500)=4800
S(4700,100)=4800
S(4700,150)=4850
S(4700,220)=4920
S(4700,330)=5030
S(4700,470)=5170
S(4700,680)=5380
S(3300,2200)=5500
S(4700,1000)=5700
S(4700,1500)=6200
S(3300,3300)=6600
S(4700,2200)=6900
S(4700,3300)=8000
S(4700,4700)=9400

Zaid

Posted 2014-05-25T23:32:40.753

Reputation: 1 015

The missing two lines are S(100)=100 and S(1000)=1000. – algorithmshark – 2014-05-28T17:23:30.400

@algorithmshark : Yup, got it. The regex was inadvertently consuming them – Zaid – 2014-05-28T19:10:46.117

It will be interesting to see if anyone can come up with a shorter Perl solution. – Zaid – 2014-05-29T16:41:27.133