javascript - Finnes det en bedre måte å skrive v=(v == 0 ? 1 : 0);
Jeg vil veksle en variabel mellom 0 og 1. Hvis den er 0, vil jeg sette den til 1, ellers hvis den er 1, vil jeg sette den til 0.
Dette er en så grunnleggende operasjon som jeg skriver så ofte at jeg gjerne vil undersøke den korteste, klareste måten å gjøre det på. Her er mitt beste så langt:
v = (v == 0 ? 1 : 0);
Kan du forbedre dette?
Rediger: spørsmålet spør om hvordan man skriver ovennevnte uttalelse med færrest mulige tegn samtidig som klarheten beholdes - hvordan er dette «ikke et ekte spørsmål»? Dette var ikke ment å være en kode-golf-øvelse, selv om noen interessante svar har kommet fra folk som har sett på det som golf - det er hyggelig å se golf bli brukt på en konstruktiv og tankevekkende måte.
Svar #1
Du kan ganske enkelt bruke:
v = 1 - v;
Dette forutsetter selvfølgelig at variabelen er initialisert riktig, det vil si at den kun har verdien 0 eller 1.
En annen metode som er kortere, men bruker en mindre vanlig operator:
v ^= 1;
Rediger :
For å være klar; jeg nærmet meg aldri dette spørsmålet som kodegolf, bare for å finne en kort måte å utføre oppgaven på uten å bruke noen skjulte triks som bivirkninger av operatorer.
Svar #2
Siden 0 er en false-verdi og 1 er en true-verdi.
v = (v ? 0 : 1);
Hvis du er fornøyd med å bruke true og false i stedet for tall
v = !v;
eller om de må være tall:
v = +!v; /* Boolean invert v then cast back to a Number */
Svar #3
v=(v + 1) % 2 og hvis du trenger å sykle gjennom flere verdier, bare endre 2 til (n + 1). Si at du trenger å sykle 0,1,2, bare gjør v=(v + 1) % 3.
Svar #4
Du kunne skrevet en funksjon for det og brukt den som:
v = inv(v)Svar #5
Hvis du ikke bryr deg om noen mulighet annet enn 1:
v = v ? 0 : 1;
I tilfellet ovenfor vil v ende opp med å være 1 hvis v er 0, false, undefined eller null. Vær forsiktig med å bruke denne typen tilnærming - v vil være 0 selv om v er "hello world".
Svar #6
Linjer som v=1 - v, eller v ^= 1 eller v= +!v får alle jobben gjort, men de utgjør det jeg vil kalle hacks. Dette er ikke vakre kodelinjer, men billige triks for å oppnå ønsket effekt. 1 - v kommuniserer ikke «veksle verdien mellom 0 og 1». Dette gjør koden din mindre uttrykksfull og introduserer et sted (om enn lite) hvor en annen utvikler må tolke koden din.
Å ha en funksjon som v=toggle(v) kommuniserer hensikten ved et raskt blikk.
Svar #7
(Ærlighet og matematisk integritet - gitt antallet stemmer på dette "svar" - har ført til at jeg har redigert dette svaret. Jeg utsatte det så lenge som mulig fordi det var ment som en kort vittighet og ikke som noe "dypt", så å legge inn noen forklaring virket mot formålet. Men kommentarene gjør det klart at jeg bør være tydelig for å unngå misforståelser.)
Mitt opprinnelige svar:
Ordlyden i denne delen av spesifikasjonen:
Hvis det er 0, vil jeg sette det til 1, ellers sette det til 0.
innebærer at den mest nøyaktige løsningen er:
v = dirac_delta(0,v)
Først, tilståelsen: Jeg blandet faktisk sammen deltafunksjonene mine. Kronecker-deltaen ville vært litt mer passende, men ikke mye, siden jeg ønsket noe som var domenen-uavhengig (Kronecker-deltaen brukes hovedsakelig bare for heltall). Men jeg burde egentlig ikke ha brukt deltafunksjoner i det hele tatt, jeg burde ha sagt:
v = characteristic_function({0},v)
La meg klargjøre. Husk at en funksjon er en triple, (X,Y,f), hvor X og Y er mengder (kalt henholdsvis domene og kodomene) og f er en regel som tilordner et element i Y til hvert element i X. Vi skriver ofte tripelen (X,Y,f) som f: X → Y. Gitt en delmengde av X, si A, finnes det en karakteristisk funksjon som er en funksjon χA: X → {0,1} (den kan også betraktes som en funksjon til et større kodomene som ℕ eller ℝ). Denne funksjonen er definert av regelen:
χA(x)=1 hvis x ∈ A og χA(x)=0 hvis x ∉ A.
Hvis du liker sannhetstabeller, er dette sannhetstabellen for spørsmålet «Er elementet x i X et element i delmengden A?».
Så fra denne definisjonen er det klart at karakteristikkfunksjonen er det som trengs her, med X som en stor mengde som inneholder 0 og A={0}. Det er det jeg burde ha skrevet.
Og så til deltafunksjoner. For dette trenger vi å vite om integrasjon. Enten vet du det allerede, eller så gjør du det ikke. Hvis du ikke gjør det, vil ingenting jeg kan si her forklare deg detaljene i teorien, men jeg kan gi en ett-setnings oppsummering. Et mål på et sett X er i hovedsak "det som trengs for å få gjennomsnitt til å fungere". Det vil si at hvis vi har et sett X og et mål μ på dette settet, så finnes det en klasse funksjoner X → ℝ, kalt målbare funksjoner, for hvilke uttrykket ∫X f dμ gir mening og på en vag måte er "gjennomsnittet" av f over X.
Gitt et mål på en mengde, kan man definere et «mål» for delmengder av den mengden. Dette gjøres ved å tilordne en delmengde integralet av dens karakteristiske funksjon (forutsatt at dette er en målbar funksjon). Dette kan være uendelig, eller udefinert (de to er subtilt forskjellige).
Det finnes mange mål der ute, men det er to som er viktige her. Ett er standardmålet på den reelle linjen, ℝ. For dette målet er ∫ℝ f dμ stort sett det du lærer på skolen (læres kalkulus fortsatt på skoler?): summer små rektangler og ta stadig mindre bredder. I dette målet er målet til et intervall dets bredde. Målet til et punkt er 0.
Et annet viktig tiltak, som fungerer på hvilket som helst sett, kalles punktmåling. Det er definert slik at integralet av en funksjon er summen av dens verdier:
∫X f dμ=∑x ∈X f(x)
Dette målet tilordner hver singletonmengde målet 1. Dette betyr at en delmengde har endelig mål hvis og bare hvis den selv er endelig. Og svært få funksjoner har endelig integral. Hvis en funksjon har et endelig integral, må den være ulik null kun på et tellbart antall punkter. Så det store flertallet av funksjoner som du sannsynligvis kjenner til, har ikke endelig integral under dette målet.
Og nå til deltafunksjoner. La oss ta en svært bred definisjon. Vi har et målbart rom (X,μ) (så det er et sett med et mål på) og et element a ∈ X. Vi «definerer» deltafunksjonen (avhengig av a) som «funksjonen» δa: X → ℝ med egenskapen at δa(x)=0 hvis x ≠ a og ∫X δa dμ=1.
Det viktigste å få tak i om dette er følgende: Deltafunksjonen trenger ikke å være en funksjon. Den er ikke korrekt definert: Jeg har ikke sagt hva δa(a) er.
Hva du gjør på dette punktet avhenger av hvem du er. Verden her deler seg inn i to kategorier. Hvis du er en matematiker, sier du følgende:
Okay, så deltafunksjonen kan hende ikke er definert. La oss se på dens hypotetiske egenskaper og se om vi kan finne et ordentlig sted for den hvor den er definert. Vi kan gjøre det, og vi ender opp med distribusjoner. Disse er ikke (nødvendigvis) funksjoner, men er ting som oppfører seg litt som funksjoner, og ofte kan vi arbeide med dem som om de var funksjoner; men det er visse ting de ikke har (som "verdier"), så vi må være forsiktige.
Hvis du ikke er matematiker, sier du følgende:
Ok, så deltafunksjonen er kanskje ikke riktig definert. Hvem sier det? En gjeng matematikere? Ignorer dem! Hva vet de?
Etter å ha fornærmet mitt publikum, skal jeg fortsette.
Dirac-deltaen blir vanligvis betraktet som deltafunksjonen for et punkt (ofte 0) på den reelle linjen med dens standardmål. Så de som klager i kommentarene på at jeg ikke kjenner mine deltas, gjør det fordi de bruker denne definisjonen. Til dem, jeg beklager: selv om jeg kan vri meg unna det ved å bruke matematikerens forsvar (som popularisert av Humpty Dumpty: rett og slett omdefiner alt slik at det blir korrekt), er det dårlig form å bruke et standardbegrep for å bety noe annet.
Men det finnes en deltafunksjon som faktisk gjør det jeg vil at den skal gjøre, og det er den jeg trenger her. Hvis jeg tar et punktmål på en mengde X, så finnes det en ekte funksjon δa : X → ℝ som oppfyller kriteriene for en deltafunksjon. Dette er fordi vi ser etter en funksjon X → ℝ som er null bortsett fra i a og slik at summen av alle dens verdier er 1. En slik funksjon er enkel: det eneste manglende informasjonselementet er verdien ved a, og for å få summen til å bli 1 gir vi den bare verdien 1. Dette er ikke noe annet enn karakteristikkfunksjonen på {a}. Så:
∫X δa dμ=∑x ∈ X δa(x)=δa(a)=1.
Så i dette tilfellet, for et singletonsett, er den karakteristiske funksjonen og deltafunksjonen enige.
Avslutningsvis er det tre familier av "funksjoner" her:
- Karakteristiske funksjoner for enkelttmengder,
- Deltafunksjonene,
- Kronecker-deltafunksjonene.
Den andre av disse er den mest generelle siden noen av de andre er et eksempel på den når man bruker punktmålingen. Men den første og tredje har fordelen av at de alltid er ekte funksjoner. Den tredje er faktisk en spesiell sak av den første, for en bestemt familie av domener (heltall, eller et delsett av disse).
Så, til slutt, da jeg opprinnelig skrev svaret, tenkte jeg ikke riktig (jeg ville ikke gå så langt som å si at jeg var forvirret, som jeg håper jeg nettopp har demonstrert at jeg faktisk vet hva jeg snakker om når jeg faktisk tenker først, jeg tenkte bare ikke så mye). Den vanlige betydningen av Dirac-deltaen er ikke det som ønskes her, men ett av poengene med svaret mitt var at inngangsområdet ikke var definert, så Kronecker-deltaen ville heller ikke ha vært riktig. Dermed ville det beste matematiske svaret (som jeg siktet mot) vært karakteristikkfunksjonen.
Jeg håper at alt dette er klart; og jeg håper også at jeg aldri må skrive et matematisk stykke igjen ved å bruke HTML-enheter i stedet for TeX-makroer!
Svar #8
generelt, når du trenger å veksle mellom to verdier, kan du bare trekke den nåværende verdien fra summen av de to vekslingsverdiene:
0,1 -> v = 1 - v 1,2 -> v = 3 - v 4,5 -> v = 9 - v
Svar #9
Du kunne gjøre
v = Math.abs(--v);
Decrementet setter verdien til 0 eller -1, og deretter konverterer Math.abs -1 til +1.
Svar #10
Hvis det må være heltallet 1 eller 0, så er måten du gjør det på grei, selv om parenteser ikke er nødvendig. Hvis disse skal brukes som boolske verdier, kan du bare gjøre:
v = !v;
Svar #11
v = v == 0 ? 1 : 0;
Er nok!
Svar #12
Liste over løsninger
Det er tre løsninger jeg ønsker å foreslå. Alle konverterer enhver verdi til 0 (hvis 1, true osv.) eller 1 (hvis 0, false, null osv.):
v = 1*!vv = +!vv = ~~!v
og en til, allerede nevnt, men smart og rask (selv om den kun fungerer for 0er og 1er):
v = 1-v
Løsning 1
Du kan bruke følgende løsning:
v = 1*!v
Dette vil først konvertere heltallet til det motsatte boolske (0 til True og enhver annen verdi til False), deretter vil det behandles som heltall når det multipliseres med 1. Som et resultat vil 0 bli konvertert til 1 og enhver annen verdi til 0.
Som bevis, se denne jsfiddle og oppgi verdier du ønsker å teste: jsfiddle.net/rH3g5/
Resultatene er som følger:
-123vil konverteres til heltall0,-10vil konverteres til heltall0,-1vil konverteres til heltall0,0vil konverteres til heltall1,1vil konverteres til heltall0,2vil konverteres til heltall0,60vil konverteres til heltall0,
Løsning 2
Som mblase75 bemerket, hadde jAndy en annen løsning som fungerer som min:
v = +!v
Det gjør det også først til en boolsk verdi fra den opprinnelige verdien, men bruker + i stedet for 1* for å gjøre det om til et heltall. Resultatet er nøyaktig det samme, men notasjonen er kortere.
Løsning 3
En annen tilnærming er å bruke ~~-operatoren:
v = ~~!v
Det er ganske uvanlig og konverterer alltid til heltall fra boolsk.
Svar #13
For å oppsummere et annet svar, en kommentar og min egen mening, foreslår jeg å kombinere to ting:
- Bruk en funksjon for bryteren
- Inne i denne funksjonen bruk en mer lesbar implementering
Her er funksjonen som du kan plassere i et bibliotek eller kanskje pakke inn i en plugin for et annet Javascript-rammeverk.
function inv(i) {
if (i == 0) {
return 1
} else {
return 0;
}
}
Og bruken er enkelt:
v = inv(v);
Fordelene er:
- Ingen kode duplisering
- Hvis du eller noen andre leser dette igjen i fremtiden, vil du forstå koden din på et minimum av tid.
Svar #14
Dette mangler:
v = [1, 0][v];
Det fungerer som rundtur også:
v = [2, 0, 1][v]; // 0 2 1 0 ...
v = [1, 2, 0][v]; // 0 1 2 0 ...
v = [1, 2, 3, 4, 5, 0][v]; // 0 1 2 3 4 5 ...
v = [5, 0, 1, 2, 3, 4][v]; // 0 5 4 3 2 1 0 ...
Eller
v = {0: 1, 1: 0}[v];
Sjarmen ved den siste løsningen er at den fungerer med alle andre verdier også.
v = {777: 'seven', 'seven': 777}[v];
For en veldig spesiell sak, som å få en (varierende) verdi og undefined, kan dette mønsteret være nyttig:
v = { undefined: someValue }[v]; // undefined someValue undefined someValue undefined ...
Svar #15
Jeg vet ikke hvorfor du vil lage dine egne boolske verdier? Jeg liker de kule syntaksene, men hvorfor ikke skrive forståelig kode?
Dette er ikke den korteste/raskeste, men den mest tydelige (og lesbare for alle) er å bruke den velkjente if/else-setningen:
if (v === 0)
{
v = 1;
}
else
{
v = 0;
}
Hvis du vil være virkelig tydelig, bør du bruke boolske verdier i stedet for tall for dette. De er raske nok for de fleste tilfeller. Med boolske verdier kan du bare bruke denne syntaksen, som vil vinne på korthet:
v = !v;
Svar #16
En annen form for din opprinnelige løsning:
v = Number(v == 0);
REDIGER: Takk til TehShrike og Guffa for å påpeke feilen i min opprinnelige løsning.
Svar #17
Jeg ville gjort det mer eksplisitt.
Hva betyr v?
For eksempel når v er en tilstand. Opprett et objekt Status. I DDD et verdobjekt.
Implementer logikken i dette verdiobjektet. Deretter kan du skrive koden din på en mer funksjonell måte som er mer lesbar. Bytting av status kan gjøres ved å lage en ny Status basert på den nåværende statusen. Din if-setning/logikk er da innkapslet i objektet ditt, som du kan lage enhetstester for. Et verdiobjekt er alltid uforanderlig, så det har ingen identitet. Så for å endre verdien må du lage et nytt.
Eksempel :
public class Status
{
private readonly int _actualValue;
public Status(int value)
{
_actualValue = value;
}
public Status(Status status)
{
_actualValue = status._actualValue == 0 ? 1 : 0;
}
//some equals method to compare two Status objects
}
var status = new Status(0);
Status = new Status(status);
Svar #18
Siden dette er JavaScript, kan vi bruke den unitære + for å konvertere til int:
v = +!v;
Dette vil logisk IKKE verdien av v (gir true hvis v == 0 eller false hvis v == 1). Deretter konverterer vi den returnerte boolske verdien til dens tilsvarende heltallsrepresentasjon.
Svar #19
En annen måte å gjøre det på:
v = ~(v|-v) >>> 31;
