Display a linear combination
- Task
Display a finite linear combination in an infinite vector basis .
Write a function that, when given a finite list of scalars ,
creates a string representing the linear combination in an explicit format often used in mathematics, that is:
where
The output must comply to the following rules:
- don't show null terms, unless the whole combination is null.
- e(1) is fine, e(1) + 0*e(3) or e(1) + 0 is wrong.
- don't show scalars when they are equal to one or minus one.
- e(3) is fine, 1*e(3) is wrong.
- don't prefix by a minus sign if it follows a preceding term. Instead you use subtraction.
- e(4) - e(5) is fine, e(4) + -e(5) is wrong.
Show here output for the following lists of scalars:
1) 1, 2, 3 2) 0, 1, 2, 3 3) 1, 0, 3, 4 4) 1, 2, 0 5) 0, 0, 0 6) 0 7) 1, 1, 1 8) -1, -1, -1 9) -1, -2, 0, -3 10) -1
EchoLisp
<lang scheme>
- build an html string from list of coeffs
(define (linear->html coeffs)
(define plus #f) (or* (for/fold (html "") ((a coeffs) (i (in-naturals 1))) (unless (zero? a) (set! plus (if plus "+" ""))) (string-append html
(cond ((= a 1) (format "%a e%d " plus i)) ((= a -1) (format "- e%d " i)) ((> a 0) (format "%a %d*e%d " plus a i)) ((< a 0) (format "- %d*e%d " (abs a) i)) (else ""))))
"0"))
(define linears '((1 2 3)
(0 1 2 3) (1 0 3 4) (1 2 0) (0 0 0) (0) (1 1 1) (-1 -1 -1) (-1 -2 0 -3) (-1)))
(define (task linears)
(html-print ;; send string to stdout (for/string ((linear linears)) (format "%a -> %a
" linear (linear->html linear)))))
</lang>
- Output:
(1 2 3) -> e1 + 2*e2 + 3*e3
(0 1 2 3) -> e2 + 2*e3 + 3*e4
(1 0 3 4) -> e1 + 3*e3 + 4*e4
(1 2 0) -> e1 + 2*e2
(0 0 0) -> 0
(0) -> 0
(1 1 1) -> e1 + e2 + e3
(-1 -1 -1) -> - e1 - e2 - e3
(-1 -2 0 -3) -> - e1 - 2*e2 - 3*e4
(-1) -> - e1
Elixir
<lang elixir>defmodule Linear_combination do
def display(coeff) do Enum.with_index(coeff) |> Enum.map_join(fn {n,i} -> {m,s} = if n<0, do: {-n,"-"}, else: {n,"+"} case {m,i} do {0,_} -> "" {1,i} -> "#{s}e(#{i+1})" {n,i} -> "#{s}#{n}*e(#{i+1})" end end) |> String.lstrip(?+) |> case do "" -> IO.puts "0" str -> IO.puts str end end
end
coeffs =
[ [1, 2, 3], [0, 1, 2, 3], [1, 0, 3, 4], [1, 2, 0], [0, 0, 0], [0], [1, 1, 1], [-1, -1, -1], [-1, -2, 0, -3], [-1] ]
Enum.each(coeffs, &Linear_combination.display(&1))</lang>
- Output:
e(1)+2*e(2)+3*e(3) e(2)+2*e(3)+3*e(4) e(1)+3*e(3)+4*e(4) e(1)+2*e(2) 0 0 e(1)+e(2)+e(3) -e(1)-e(2)-e(3) -e(1)-2*e(2)-3*e(4) -e(1)
J
Implementation:
<lang J>fourbanger=:3 :0
e=. ('e(',')',~])@":&.> 1+i.#y firstpos=. 0< {.y-.0 if. */0=y do. '0' else. firstpos}.;y gluedto e end.
)
gluedto=:4 :0 each
pfx=. '+-' {~ x<0 select. |x case. 0 do. case. 1 do. pfx,y case. do. pfx,(":|x),'*',y end.
)</lang>
Example use:
<lang J> fourbanger 1 2 3 e(1)+2*e(2)+3*e(3)
fourbanger 0 1 2 3
e(2)+2*e(3)+3*e(4)
fourbanger 1 0 3 4
e(1)+3*e(3)+4*e(4)
fourbanger 0 0 0
0
fourbanger 0
0
fourbanger 1 1 1
e(1)+e(2)+e(3)
fourbanger _1 _1 _1
-e(1)-e(2)-e(3)
fourbanger _1 _2 0 _3
-e(1)-2*e(2)-3*e(4)
fourbanger _1
-e(1)</lang>
Perl 6
<lang perl6>sub linear-combination(@coeff) {
(@coeff Z=> map { "e($_)" }, 1 .. *) .grep(+*.key) .map({ .key ~ '*' ~ .value }) .join(' + ') .subst('+ -', '- ', :g) .subst(/<|w>1\*/, , :g) || '0'
}
say linear-combination($_) for [1, 2, 3], [0, 1, 2, 3], [1, 0, 3, 4], [1, 2, 0], [0, 0, 0], [0], [1, 1, 1], [-1, -1, -1], [-1, -2, 0, -3], [-1 ]
- </lang>
- Output:
e(1) + 2*e(2) + 3*e(3) e(2) + 2*e(3) + 3*e(4) e(1) + 3*e(3) + 4*e(4) e(1) + 2*e(2) 0 0 e(1) + e(2) + e(3) -e(1) - e(2) - e(3) -e(1) - 2*e(2) - 3*e(4) -e(1)
Python
<lang python> def linear(x):
return ' + '.join(['{}e({})'.format('-' if v == -1 else if v == 1 else str(v) + '*', i + 1) for i, v in enumerate(x) if v] or ['0']).replace(' + -', ' - ')
list(map(lambda x: print(linear(x)), [[1, 2, 3], [0, 1, 2, 3], [1, 0, 3, 4], [1, 2, 0],
[0, 0, 0], [0], [1, 1, 1], [-1, -1, -1], [-1, -2, 0, 3], [-1]]))
</lang>
- Output:
e(1) + 2*e(2) + 3*e(3) e(2) + 2*e(3) + 3*e(4) e(1) + 3*e(3) + 4*e(4) e(1) + 2*e(2) 0 0 e(1) + e(2) + e(3) -e(1) - e(2) - e(3) -e(1) - 2*e(2) + 3*e(4) -e(1)
Racket
<lang racket>#lang racket/base (require racket/match racket/string)
(define (linear-combination->string es)
(let inr ((es es) (i 1) (rv "")) (match* (es rv) [((list) "") "0"] [((list) rv) rv] [((list (? zero?) t ...) rv) (inr t (add1 i) rv)] [((list n t ...) rv) (define ±n (match* (n rv) ;; zero is handled above [(1 "") ""] [(1 _) "+"] [(-1 _) "-"] [((? positive? n) (not "")) (format "+~a*" n)] [(n _) (format "~a*" n)])) (inr t (add1 i) (string-append rv ±n "e("(number->string i)")"))])))
(for-each
(compose displayln linear-combination->string) '((1 2 3) (0 1 2 3) (1 0 3 4) (1 2 0) (0 0 0) (0) (1 1 1) (-1 -1 -1) (-1 -2 0 -3) (-1)))
</lang>
- Output:
e(1)+2*e(2)+3*e(3) e(2)+2*e(3)+3*e(4) e(1)+3*e(3)+4*e(4) e(1)+2*e(2) 0 0 e(1)+e(2)+e(3) -e(1)-e(2)-e(3) -e(1)-2*e(2)-3*e(4) -e(1)
REXX
<lang rexx>/*REXX program displays a finite liner combination in an infinite vector basis. */ @.=.; @.1 = '1, 2, 3'
@.2 = '0, 1, 2, 3' @.3 = '1, 0, 3, 4' @.4 = '1, 2, 0' @.5 = '0, 0, 0' @.6 = 0 @.7 = '1, 1, 1' @.8 = '-1, -1, -1' @.9 = '-1, -2, 0, -3' @.10 = -1 do j=1 while @.j\==.; n=0 /*process each vector; zero element cnt*/ y=space( translate(@.j, ,',') ) /*elide commas and superfluous blanks. */ $= /*nullify output (liner combination).*/ do k=1 for words(y); #=word(y, k) /* ◄───── process each of the elements.*/ if #=0 then iterate; a=abs(# / 1) /*if the value is zero, then ignore it.*/ s='+ '; if #<0 then s='- ' /*define the sign: plus(+) or minus(-)*/ n=n+1; if n==1 then s=strip(s) /*if the 1st element used, remove plus.*/ if a\==1 then s=s || a'*' /*if multiplier is unity, then ignore #*/ $=$ s'e('k")" /*construct a liner combination element*/ end /*k*/
$=strip( strip($), 'L', "+") /*strip leading plus sign (1st element)*/ if $== then $=0 /*handle special case of no elements. */ say right( space(@.j), 20) ' ──► ' strip($) /*align the output for presentation. */ end /*j*/ /*stick a fork in it, we're all done. */</lang>
output when using the default inputs:
1, 2, 3 ──► e(1) + 2*e(2) + 3*e(3) 0, 1, 2, 3 ──► e(2) + 2*e(3) + 3*e(4) 1, 0, 3, 4 ──► e(1) + 3*e(3) + 4*e(4) 1, 2, 0 ──► e(1) + 2*e(2) 0, 0, 0 ──► 0 0 ──► 0 1, 1, 1 ──► e(1) + e(2) + e(3) -1, -1, -1 ──► -e(1) - e(2) - e(3) -1, -2, 0, -3 ──► -e(1) - 2*e(2) - 3*e(4) -1 ──► -e(1)
Tcl
This solution strives for legibility rather than golf.
<lang Tcl>proc lincom {factors} {
set exp 0 set res "" foreach f $factors { incr exp if {$f == 0} { continue } elseif {$f == 1} { append res "+e($exp)" } elseif {$f == -1} { append res "-e($exp)" } elseif {$f > 0} { append res "+$f*e($exp)" } else { append res "$f*e($exp)" } } if {$res eq ""} {set res 0} regsub {^\+} $res {} res return $res
}
foreach test {
{1 2 3} {0 1 2 3} {1 0 3 4} {1 2 0} {0 0 0} {0} {1 1 1} {-1 -1 -1} {-1 -2 0 -3} {-1}
} {
puts [format "%10s -> %-10s" $test [lincom $test]]
}</lang>
- Output:
1 2 3 -> e(1)+2*e(2)+3*e(3) 0 1 2 3 -> e(2)+2*e(3)+3*e(4) 1 0 3 4 -> e(1)+3*e(3)+4*e(4) 1 2 0 -> e(1)+2*e(2) 0 0 0 -> 0 0 -> 0 1 1 1 -> e(1)+e(2)+e(3) -1 -1 -1 -> -e(1)-e(2)-e(3) -1 -2 0 -3 -> -e(1)-2*e(2)-3*e(4) -1 -> -e(1)
zkl
<lang zkl>fcn linearCombination(coeffs){
[1..].zipWith(fcn(n,c){ if(c==0) "" else "%s*e(%s)".fmt(c,n) },coeffs) .filter().concat("+").replace("+-","-").replace("1*","") or 0
}</lang> <lang zkl>T(T(1,2,3),T(0,1,2,3),T(1,0,3,4),T(1,2,0),T(0,0,0),T(0),T(1,1,1),T(-1,-1,-1),
T(-1,-2,0,-3),T(-1),T)
.pump(Console.println,linearCombination);</lang>
- Output:
e(1)+2*e(2)+3*e(3) e(2)+2*e(3)+3*e(4) e(1)+3*e(3)+4*e(4) e(1)+2*e(2) 0 0 e(1)+e(2)+e(3) -e(1)-e(2)-e(3) -e(1)-2*e(2)-3*e(4) -e(1) 0