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.trim_leading("+") |> 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>
Julia
<lang julia># v0.6
linearcombination(coef::Array) = join(collect("$c * e($i)" for (i, c) in enumerate(coef) if c != 0), " + ")
for c in [[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]] @printf("%20s -> %s\n", c, linearcombination(c))
end</lang>
- Output:
[1, 2, 3] -> 1 * e(1) + 2 * e(2) + 3 * e(3) [0, 1, 2, 3] -> 1 * e(2) + 2 * e(3) + 3 * e(4) [1, 0, 3, 4] -> 1 * e(1) + 3 * e(3) + 4 * e(4) [1, 2, 0] -> 1 * e(1) + 2 * e(2) [0, 0, 0] -> [0] -> [1, 1, 1] -> 1 * e(1) + 1 * e(2) + 1 * e(3) [-1, -1, -1] -> -1 * e(1) + -1 * e(2) + -1 * e(3) [-1, -2, 0, -3] -> -1 * e(1) + -2 * e(2) + -3 * e(4) [-1] -> -1 * e(1)
Kotlin
<lang scala>// version 1.1.2
fun linearCombo(c: IntArray): String {
val sb = StringBuilder() for ((i, n) in c.withIndex()) { if (n == 0) continue val op = when { n < 0 && sb.isEmpty() -> "-" n < 0 -> " - " n > 0 && sb.isEmpty() -> "" else -> " + " } val av = Math.abs(n) val coeff = if (av == 1) "" else "$av*" sb.append("$op${coeff}e(${i + 1})") } return if(sb.isEmpty()) "0" else sb.toString()
}
fun main(args: Array<String>) {
val combos = arrayOf( intArrayOf(1, 2, 3), intArrayOf(0, 1, 2, 3), intArrayOf(1, 0, 3, 4), intArrayOf(1, 2, 0), intArrayOf(0, 0, 0), intArrayOf(0), intArrayOf(1, 1, 1), intArrayOf(-1, -1, -1), intArrayOf(-1, -2, 0, -3), intArrayOf(-1) ) for (c in combos) { println("${c.contentToString().padEnd(15)} -> ${linearCombo(c)}") }
}</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)
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)
Ring
<lang ring> scalars = [[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]] for n=1 to len(scalars)
str = "" for m=1 to len(scalars[n]) scalar = scalars[n] [m] if scalar != "0" if scalar = 1 str = str + "+e" + m elseif scalar = -1 str = str + "" + "-e" + m else if scalar > 0 str = str + char(43) + scalar + "*e" + m else str = str + "" + scalar + "*e" + m ok ok ok next if str = "" str = "0" ok if left(str, 1) = "+" str = right(str, len(str)-1) ok see str + nl
next </lang> Output:
e1+2*e2+3*e3 e2+2*e3+3*e4 e1+3*e3+4*e4 e1+2*e2 0 0 e1+e2+e3 -e1-e2-e3 -e1-2*e2-3*e4 -e1
Sidef
<lang ruby>func linear_combination(coeffs) {
var res = "" for e,f in (coeffs.kv) { given(f) { when (1) { res += "+e(#{e+1})" } when (-1) { res += "-e(#{e+1})" } case (.> 0) { res += "+#{f}*e(#{e+1})" } case (.< 0) { res += "#{f}*e(#{e+1})" } } } res -= /^\+/ res || 0
}
var tests = [
%n{1 2 3}, %n{0 1 2 3}, %n{1 0 3 4}, %n{1 2 0}, %n{0 0 0}, %n{0}, %n{1 1 1}, %n{-1 -1 -1}, %n{-1 -2 0 -3}, %n{-1},
]
tests.each { |t|
printf("%10s -> %-10s\n", t.join(' '), linear_combination(t))
}</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)
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