Il fenomeno di Will Rogers


35

Il cosiddetto fenomeno Will Rogers descrive un modo per modificare le statistiche aumentando la media in due (multi) set quando un elemento viene spostato tra i due set. Come semplice esempio, considera i due set

A = {1, 2, 3}
B = {4, 5, 6}

I loro mezzi aritmetici sono 2e 5, rispettivamente. Se spostiamo il 4a A:

A = {1, 2, 3, 4}
B = {5, 6}

Ora le medie sono 2.5e 5.5, rispettivamente, quindi entrambe le medie sono state aumentate attraverso un semplice raggruppamento.

Come altro esempio, considera

A = {3, 4, 5, 6} --> A = {3, 5, 6}
B = {2, 3, 4, 5} --> B = {2, 3, 4, 4, 5}

D'altra parte, non è possibile aumentare entrambe le medie per i set

A = {1, 5, 9}
B = {4, 5, 7, 8}

La sfida

Dati due elenchi di numeri interi non negativi, determinare se è possibile aumentare entrambe le medie spostando un singolo numero intero da un elenco all'altro.

La media di un elenco vuoto non è definita, quindi se uno degli elenchi contiene solo un elemento, questo elemento non può essere spostato.

È possibile scrivere un programma o una funzione, prendendo l'input tramite STDIN (o l'alternativa più vicina), l'argomento della riga di comando o l'argomento della funzione e producendo il risultato tramite STDOUT (o l'alternativa più vicina), il valore di ritorno della funzione o il parametro della funzione (out).

L'input può essere preso in qualsiasi formato stringa o elenco conveniente.

Non si deve presumere che gli elementi di ciascun elenco siano univoci, né che siano ordinati. Si può presumere che entrambi gli elenchi contengano almeno un elemento.

L'output dovrebbe essere veritiero se entrambe le medie possono essere aumentate spostando un singolo intero e falsando diversamente.

Questo è il golf del codice, quindi vince la risposta più breve (in byte).

Casi test

Truthy:

[1], [2, 3]
[1, 2, 3], [4, 5, 6]
[3, 4, 5, 6], [2, 3, 4, 5]
[6, 5, 9, 5, 6, 0], [6, 2, 0, 9, 5, 2]
[0, 4], [9, 1, 0, 2, 8, 0, 5, 5, 4, 9]

Falsy:

[1], [2]
[2, 4], [5]
[1, 5], [2, 3, 4, 5]
[2, 1, 2, 3, 1, 3], [5, 1, 6]
[4, 4, 5, 2, 4, 0], [9, 2, 10, 1, 9, 0]

Classifiche

Ecco uno snippet di stack per generare sia una classifica regolare che una panoramica dei vincitori per lingua.

Per assicurarti che la tua risposta venga visualizzata, ti preghiamo di iniziare la risposta con un titolo, usando il seguente modello Markdown:

# Language Name, N bytes

dov'è Nla dimensione del tuo invio. Se si migliora il punteggio, è possibile mantenere i vecchi punteggi nel titolo, colpendoli. Per esempio:

# Ruby, <s>104</s> <s>101</s> 96 bytes

<script>site = 'meta.codegolf'; postID = 5314; isAnswer = true; QUESTION_ID = 53913</script><script src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js'></script><script>jQuery(function(){var u='https://api.stackexchange.com/2.2/';if(isAnswer)u+='answers/'+postID+'?order=asc&sort=creation&site='+site+'&filter=!GeEyUcJFJeRCD';else u+='questions/'+postID+'?order=asc&sort=creation&site='+site+'&filter=!GeEyUcJFJO6t)';jQuery.get(u,function(b){function d(s){return jQuery('<textarea>').html(s).text()};function r(l){return new RegExp('<pre class="snippet-code-'+l+'\\b[^>]*><code>([\\s\\S]*?)</code></pre>')};b=b.items[0].body;var j=r('js').exec(b),c=r('css').exec(b),h=r('html').exec(b);if(c!==null)jQuery('head').append(jQuery('<style>').text(d(c[1])));if (h!==null)jQuery('body').append(d(h[1]));if(j!==null)jQuery('body').append(jQuery('<script>').text(d(j[1])))})})</script>


Come matematico e non programmatore, non riesco davvero ad affrontare la sfida, ma sono interessato alla seguente domanda: se entrambe le medie possono essere aumentate spostando una raccolta finita di numeri interi (diciamo cinque) da una serie all'altra , ne consegue sempre che entrambe le medie possono essere aumentate spostando solo un numero intero ? Dimostrando così che la sfida copre davvero tutti i casi.
Trevor J Richards,

3
@TrevorRichards Penso che l'ultimo caso di falsy test riguardi questo. Potresti spostare una 1e 9più volte, il che aumenterebbe entrambe le medie, ma non puoi farlo spostandone una singola.
Martin Ender,

@TrevorRichards In generale, se gli insiemi A e B hanno medie a & b con a <b, entrambe le medie possono essere aumentate se esiste un sottoinsieme C di B che ha una media c tale che a <c <b. D'altra parte, se richiedi che tutti gli elementi spostati da B ad A abbiano valori <b, allora la tua ipotesi sarebbe vera.
Alchymist

Risposte:


11

Pyth, 29 28 26 24 byte

Grazie a @Jakube per avermi salvato 3 byte con .pe L.

Molto semplice, controlla se qualche elemento nell'elenco 2 è maggiore della media dell'elenco 1 e inferiore alla media dell'elenco 2, quindi si ripete con l'elenco 1 e l'elenco 2 commutati.

Lcsblbff&>YyhT<YyeTeT.pQ

Stampa un elenco non vuoto per verità e []per falsità.

L                    Define y(b). Pyth has no builtin for mean
 c                   Float div
  sb                 Sum of b
  lb                 Length of b
f        .pQ         Filter all permutations of input
 f     eT            Filter the last element of the filter var
  &                  Logical and
   >Y                Inner filter var greater than
    y                Call the mean function we defined earlier
     hT              First element of outer filter var
   <Y                Inner filter var less than
    y                Mean of
     eT              Last element of outer filternvar

Provalo online qui .

Test Suite.


7

Python 3, 74

lambda*L:any(sum(C)/len(C)>x>sum(D)/len(D)for(C,D)in[L,L[::-1]]for x in C)

Accetta due elenchi come input. Verifica se il primo elenco ha un elemento più grande della media ma più piccolo dell'altro. Quindi, fa lo stesso per i due ingressi scambiati. La comprensione di un elenco a due livelli era più breve della definizione di una funzione separata per provare i due ordini (82):

f=lambda A,B:any(sum(A)/len(A)>x>sum(B)/len(B)for x in A)
lambda A,B:f(A,B)|f(B,A)

7

Haskell, 58 57

x%y=any(\n->(\g->g x<0&&g y>0)$sum.map(n-))x
x?y=x%y||y%x

possiamo verificare se allarghiamo o abbassiamo la media controllando se l'elemento da rimuovere o includere è più grande o più piccolo della media.

possiamo verificarlo controllando se la media è più piccola o più grande di un elemento rimuovendo quell'elemento dalla matrice e verificando se la media della nuova matrice è negativa o positiva, il che a sua volta è proprio come verificare se la somma è positiva o negativa .

controllo che è messo molto semplicemente come sum.map(-n+).


6

Mathematica, 49 47 byte

m=Mean;MemberQ[#2,x_/;m@#<x<m@#2]&@@#~SortBy~m&

Valuta una funzione pura che prevede input nel modulo {list1, list2}.


4

APL, 45 40 byte

5 byte salvati grazie a Moris Zucca!

{U←∊⍺⍵[⊃⍒M←(+/÷≢)¨⍺⍵]⋄1∊(U<⌈/M)∧(U>⌊/M)}

Questo crea una funzione diadica senza nome che accetta array a sinistra e a destra e restituisce 1 o 0.

{
  M←(+/÷≢)¨⍺⍵          ⍝ Compute the mean of each array
  U←∊⍺⍵[⊃⍒M]           ⍝ Get the array with the larger mean
  1∊(U<⌈/M)∧(U>⌊/M)    ⍝ Any smaller mean < U < larger mean
}

Puoi provarlo online .


1
puoi scrivere la media come: (+ / ÷ ≢)
Moris Zucca,

@MorisZucca Grazie! Modificato per utilizzare il tuo suggerimento.
Alex A.

3

R, 66 52 byte

Come una funzione senza nome, che accetta 2 vettori. Mi sono liberato di alcuni falsi.

function(a,b)any(a<(m=mean)(a)&a>m(b),b<m(b)&b>m(a))

test

> f=
+ function(a,b)any(a<(m=mean)(a)&a>m(b),b<m(b)&b>m(a))
> f(c(1), c(2, 3))
[1] TRUE
> f(c(1, 2, 3), c(4, 5, 6))
[1] TRUE
> f(c(3, 4, 5, 6), c(2, 3, 4, 5))
[1] TRUE
> f(c(6, 5, 9, 5, 6, 0), c(6, 2, 0, 9, 5, 2))
[1] TRUE
> f(c(0, 4), c(9, 1, 0, 2, 8, 0, 5, 5, 4, 9))
[1] TRUE
> 
> f(c(1), c(2))
[1] FALSE
> f(c(2, 4), c(5))
[1] FALSE
> f(c(1, 5), c(2, 3, 4, 5))
[1] FALSE
> f(c(2, 1, 2, 3, 1, 3), c(5, 1, 6))
[1] FALSE
> f(c(4, 4, 5, 2, 4, 0), c(9, 2, 10, 1, 9, 0))
[1] FALSE
> 

3

SAS / IML, 67

start m(a,b);return((a>b[:]&&a<a[:])||(b>a[:]&&b<b[:]))[<>];finish;

Utilizza gli operatori di riduzione dei pedici per ottenere la risposta, restituendo 0 se non viene trovato alcun elemento che soddisfa i requisiti o 1 se ne viene trovato uno.

Non golfato, qui restituisco il valore effettivo stesso utilizzando la moltiplicazione della matrice:

proc iml;
  b={1 2 3 4 5 6 7 8 9 };
  a={2 3 4 5 6};
  start m(a,b);
  return (a#(a>b[:] && a < a[:]) || b#(b>a[:] && b < b[:]))[<>];
  finish;

  z= m(a,b);
  print z;
quit;

test:

%macro test(a,b,n);
  z&n=m({&a},{&b});
  print z&n;
%mend test;

proc iml;
  b={1 2 3 4 5 };
  a={2 3 4 5 6 7};
start m(a,b);return((a>b[:]&&a<a[:])||(b>a[:]&&b<b[:]))[<>];finish;

* True;
 %test(1,2 3,1);
 %test(1 2 3,4 5 6,2);
 %test(3 4 5 6, 2 3 4 5,3);
 %test(6 5 9 5 6 0,6 2 0 9 5 2,4);
 %test(0 4, 9 1 0 2 8 0 5 5 4 9,5);
* False;
 %test(1,2,6);
 %test(2 4, 5,7);
 %test(1 5, 2 3 4 5,8);
 %test(2 1 2 3 1 3, 5 1 6,9);
 %test(4 4 5 2 4 0, 9 2 10 1 9 0,10);

quit;

(Condensato per leggibilità)

z1 1

z2 1

z3 1

z4 1

z5 1

z6 0

z7 0

z8 0

z9 0

z10 0


2

Python 2.7, 102 98 96

lambda p:any([1for i in 0,1for e in p[i]if g[i^1]<e<g[i]]for g in[[sum(l)*1./len(l)for l in p]])

Prende l'input come array dei 2 input e restituisce valori booleani.
La logica è -trovare la media delle 2 liste, quindi trovare un elemento tale che sia inferiore alla media della propria lista e maggiore della media dell'altra lista.

Il test per gli input indicati è demo qui


2
Puoi fare *1.invece di *1.0salvare un byte. In alternativa, se lo fai in Python 3, la divisione restituirà un float di default, quindi non avrai bisogno di quella moltiplicazione. (Non credo che dovresti cambiare il tuo codice per usare Python 3.)
mathmandan,

@mathmandan Mi ha salvato un byte. Grazie :)
Kamehameha,

Puoi renderlo una funzione anonima rimuovendolo f=e modificandolo in[0,1]forin in 0,1for. Dato che in realtà sei a 101 byte, questo ti porta a 98.
Kade,

@Vioz- Grazie, non sapevo che potevo farlo :)
Kamehameha,

2

CJam, 28 byte

{{_:+1$,d/\+}%$~(m],@0=i)>&}

Questa è una funzione anonima che estrae una matrice bidimensionale dalla pila e lascia in cambio una matrice di elementi mobili.

Nei browser supportati, è possibile verificare tutti i casi di test contemporaneamente nell'interprete CJam .

Casi test

Codice

q~]{{_:+1$,d/\+}%$~(m],@0=i)>&}%:p

Ingresso

[[1] [2 3]]
[[1 2 3] [4 5 6]]
[[3 4 5 6] [2 3 4 5]]
[[6 5 9 5 6 0] [6 2 0 9 5 2]]
[[0 4] [9 1 0 2 8 0 5 5 4 9]]
[[1] [2]]
[[2 4] [5]]
[[1 5] [2 3 4 5]]
[[2 1 2 3 1 3] [5 1 6]]
[[4 4 5 2 4 0] [9 2 10 1 9 0]]

Produzione

[2]
[4]
[4]
[5]
[4]
""
""
""
""
""

Come funziona

Se A e B sono le matrici e avg (A) ≤ avg (B) verifichiamo semplicemente se B ∩ {⌊avg (A) ⌋ + 1,…, ⌈avg (B) ⌉-1} non è vuoto. Qualsiasi elemento in questa intersezione può essere spostato da B ad A per aumentare entrambe le medie.

{          }%              e# For each of the arrays:
 _:+                       e#   Compute the sum of its elements.
    1$,                    e#   Compute its length.
       d/                  e#   Cast to Double and perform division.
         \+                e#   Prepend the computed average to the array.
             $             e# Sort the arrays (by the averages).
              ~            e# Dump both arrays on the stack.
               (           e# Shift out the higher average.
                m]         e# Round up to the nearest integer b.
                  ,        e# Push [0 ... b-1].
                   @0=     e# Replace the array with lower average by its average.
                      i)   e# Round down to the nearest integer a and add 1.
                        >  e# Skip the first a integer of the range.
                           e# This pushes [a+1 ... b-1].
                         & e# Intersect the result with the remaining array.

Questo spinge l'array di tutti gli elementi dell'array con una media più alta che può essere spostata per aumentare entrambe le medie. Questa matrice è vuota / falsa se e solo se non è possibile spostare alcun elemento per ottenere questo risultato.


1

Ruby, 86

A=->x{x.reduce(0.0,:+)/x.size}
F=->q{b,a=q.sort_by{|x|A[x]};a.any?{|x|x<A[a]&&x>A[b]}}

Accetta come input un array contenente i due array.

Tenta di trovare un elemento sotto la media del gruppo con la media più alta che è maggiore della media dell'altro gruppo.

Test: http://ideone.com/444W4U


Ha iniziato a lavorare su questo senza accorgersi che esisteva già una soluzione Ruby, ha finito con qualcosa di molto simile, ma mette in rete due caratteri in meno avendo la funzione di assumere che il primo elenco sia "migliore", quindi chiamarsi viceversa. f=->a,s=1{i,j=a.map{|x|x.inject(0.0,:+)/x.size};a[0].any?{|y|i>y&&j<y}||s&&f[b,a,p]}
istocratico,

@histocrat Approccio piacevole! Ottengo un NameError per quanto riguarda la variabile bperò. Penso che la chiamata ricorsiva dovrebbe essere qualcosa di simile f[a.rotate,p].
Cristian Lupascu,

1
Oops, è così che ho ottenuto un punteggio migliore, ingannando.
istocratico

1

Matlab, 54

Utilizzando una funzione anonima:

f=@(A,B)any([B>mean(A)&B<mean(B) A>mean(B)&A<mean(A)])

Esempi:

>> f=@(A,B)any([B>mean(A)&B<mean(B) A>mean(B)&A<mean(A)])
f = 
    @(A,B)any([B>mean(A)&B<mean(B),A>mean(B)&A<mean(A)])

>> f([1 2 3],[4 5 6])
ans =
     1

>> f([3 4 5 6],[2 3 4 5])
ans =
     1

>> f([1 5 9],[4 5 7 8])
ans =
     0

1

C #, 104

bool f(int[]a,int[]b){double i=a.Average(),j=b.Average();return a.Any(x=>x<i&&x>j)||b.Any(x=>x<j&&x>i);}

Chiamate di esempio:

f(new []{1,2,3}, new []{4,5,6})
f(new []{1}, new []{2, 3})
f(new []{1, 2, 3}, new []{4, 5, 6})
f(new []{3, 4, 5, 6}, new []{2, 3, 4, 5})
f(new []{6, 5, 9, 5, 6, 0}, new []{6, 2, 0, 9, 5, 2})
f(new []{0, 4}, new []{9, 1, 0, 2, 8, 0, 5, 5, 4, 9})

f(new []{1}, new []{2})
f(new []{2, 4}, new []{5})
f(new []{1, 5}, new []{2, 3, 4, 5})
f(new []{2, 1, 2, 3, 1, 3}, new []{5, 1, 6})
f(new []{4, 4, 5, 2, 4, 0}, new []{9, 2, 10, 1, 9, 0})

0

C ++ 14, 157 byte

Come senza nome lambda, ritorna dall'ultimo parametro r. Presuppone A, Bper essere contenitori come vector<int>o array<int,>.

[](auto A,auto B,int&r){auto m=[](auto C){auto s=0.;for(auto x:C)s+=x;return s/C.size();};r=0;for(auto x:A)r+=x<m(A)&&x>m(B);for(auto x:B)r+=x<m(B)&&x>m(A);}

Ungolfed:

auto f=
[](auto A,auto B,int&r){
  auto m=[](auto C){
   auto s=0.;
   for(auto x:C) s+=x;
   return s/C.size();
  };
  r=0;
  for (auto x:A) r+=x<m(A)&&x>m(B);
  for (auto x:B) r+=x<m(B)&&x>m(A);
}
;

Uso:

int main() {
  std::vector<int>
    a={1,2,3}, b={4,5,6};
  //  a={1,5,9}, b={4,5,7,8};
  int r;
  f(a,b,r);
  std::cout << r << std::endl;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.