Swap the two largest elements in a vector

Hello, good afternoon and Happy new Year.

I would like to know how I can swap the two largest elements in a vector like [1, 2, 3, 4, 5]

Simple, straight-forward implementation:

function swap_largest!(v)
    L = length(v)
    L<2 && error("vector must have two elements at least")
    i1, i2 = v[1] > v[2] ? (1,2) : (2,1)
    e1, e2 = v[i1], v[i2]
    for i in 3:L
        if v[i] > e2
            if v[i] > e1
                i1, i2 = i, i1
                e1, e2 = v[i], e1
            else
                i2 = i
                e2 = v[i]
            end
        end
    end
    v[i1], v[i2] = v[i2], v[i1]
    return v
end
8 Likes

You can use :

x = [only(findall(==(x), a)) for x in sort(a)[end - 1: end]]

a[x[1]], a[x[2]] = a[x[2]], a[x[1]]
3 Likes

I read about findmax function and was trying to build a solution with it. I’ll read about findall. Seems very neat.

It can also be done in a one-liner:

swap_largest2!(v) = 
  ( reverse!(@view v[Base.partialsortperm(v, 1:2; rev=true)]) ; v )

but the loooong version is faster I suppose (with the addition of some @inbounds on the for loop)

3 Likes

very nice also. Im getting the ? help for all these functions. The @mohamed.d180 one I already understood :slight_smile:

marked @mohamed.d180 solution because its the simplest one. Thank you all.

1 Like

For simplicity:

v = collect(1:5)
i1, i2 = partialsortperm(v, 1:2; rev=true)
v[i1], v[i2] = v[i2], v[i1]
8 Likes

For variety we can use nlargest from DataStructures as follows :

using DataStructures

x = findall(!=(nothing), indexin(a, nlargest(2, a)))

a[x[1]], a[x[2]] = a[x[2]], a[x[1]]
3 Likes

Here is the result of the code. Linear algebra is hard :sweat_smile:. A dense topic

image

if v[i]>=0

v=[1,3,2,5,4,7,8,6]
M1,p1=findmax(v)
v[p1]=-M1
M2,p2=findmax(v)


v[p1], v[p2]= M2, M1

for each v not containing missing

M1,p1=findmax(v)
v[p1]=findmin(v)[1]
M2,p2=findmax(v)
v[p1], v[p2]= M2, M1
1 Like

@jcbritobr This first does a full sort of a, allocating a copy in the process, and then searches through a twice more, before doing the swap. Perhaps performance is not very important, but it’s doing a lot of unnecessary work. Especially doing a full sort is really not nice.

1 Like

If performance is important we may use this algorithm which will be of O(n)

function swap!(a)
    i_max = argmax(a)
    i_second = argmin(a)
    d = a[i_max] - a[i_second]     # make this difference minimum to get the second max value 
    for i in 1:length(a)
        diff = a[i_max] - a[i]
        if 0 < diff < d
            i_second = i
            d = diff
        end
    end
    a[i_max], a[i_second] = a[i_second], a[i_max]
return a
end

swap!(a)

fold allocates (i don’t know wy)

function swapL2(v)
    new((a,b),c)=v[c]>v[b] ? (b,c) : (v[c]>v[a] ? (c,b) : (a,b))
    p1,p2=foldl(new, 3:length(v), init=sortperm(@view v[1:2]) )
    v[p1],v[p2]=v[p2],v[p1]
    v
end

also this doesn’t allocate

function swapl2_(v)
    M1,p1=findmax(v)
    v[p1]=findmin(v)[1]
    M2,p2=findmax(v)
    v[p1], v[p2]= M2, M1
    v
end

but swapL2 is faster than swapl2_ and both seem faster than swap!()

PS
this reinforces in me the belief that the “appropriate” use of a functional solution (with library functions written by experts) performs better than my for loops.

2 Likes