in JS, I have a list of variables, which I shuffle. I want to maintain the order of the shuffle, but change the values of the variables in the list. Is there a way to do that? Below is an example of my code. I explain what I want in the comments.
<p id="demo"></p>
<script>
var gen = "male "
var race = "white "
var rel = "christian "
var chars =[gen,race,rel]
chars = shuffle(chars);
document.getElementById("demo").innerHTML = chars+"";
/*prints for example "white christian male " which is what I want
/*lets say I want to change the gender, and maintain the newly shuffled order (race-rel-gen in this case)*/
/* The below doesn't work. I want it to print "white christian female ", but it just reprints the original string*/
gen = "female "
document.getElementById("demo").innerHTML = chars+"";
</script>
Considering you want to maintain the pre-shuffled order, you can try to use an object, instead of string, then it'll keep reference. Something like this:
/* function to convert your array of objects into a pretty string */
const arrtoStr = (arr) => arr.map((obj) => obj.value).join(' ')
var gen = { value: "male" }
var race = { value: "white" }
var rel = { value: "christian" }
var chars =[gen,race,rel]
chars = shuffle(chars);
//will output, for instance: "white christian male"
document.getElementById("demo").innerHTML = arrtoStr(chars);
// change object's key named 'value'
gen.value = "female"
//will output: "white christian female"
document.getElementById("demo").innerHTML = arrtoStr(chars);
You can use a map object and some supplemental functions to take care of this.
let char = new Map([
['gen', 'male'],
['race', 'white'],
['rel', 'christian'],
["order", shuffle([0,1,2])],
["display", ['gen', 'race', 'rel']]
]);
function shuffle(arr) {
return arr.sort(_ => Math.random() > .5);
}
function display(mItm) {
return mItm.get("order").map(itm => mItm.get(mItm.get("display")[itm]));
}
//display char
document.querySelector("#demo").innerHTML += "</br>" + display(char);
//display new race
char.set("race", "blue");
document.querySelector("#demo").innerHTML += "</br>" + display(char);
// reshuffle
char.set("order", shuffle(char.get("order")));
document.querySelector("#demo").innerHTML += "</br>" + display(char);
<p id="demo"></p>
If I understand correctly, the solution below should work. Keeping a person object and an order array separate should give you more flexibility. I am using Lodash for shuffle as a convenience.
CodePen Demo
this.person = {
gen: "male",
race: "white",
rel: "christian"
};
this.order = ["gen", "race", "rel"];
function output() {
let temp = [];
this.order.forEach((key) => {
temp.push(this.person[key]);
});
document.getElementById("demo").innerHTML += temp.join(", ") + "<br>";
}
// shuffle the order of properties
_.shuffle(this.order);
// output original data
output();
// change specifics, but keep the order of properties
this.person["gen"] = "female";
output();
this.person["race"] = "black";
output();
this.person["rel"] = "jewish";
output();
You can either assign the array again after assigning the new variable value like this:
var gen = "male "
var race = "white "
var rel = "christian "
var chars =[gen,race,rel]
chars = shuffle(chars);
document.getElementById("demo").innerHTML = chars+"";
gen = "female "
var chars =[gen,race,rel]
chars = shuffle(chars);
document.getElementById("demo").innerHTML = chars+"";
jsFiddle: https://jsfiddle.net/AndrewL64/p6rgo01a/
Or create a reusable function like this:
function newVal(gen, race, rel) {
var chars =[gen,race,rel]
chars = shuffle(chars);
document.getElementById("demo").innerHTML = chars+"";
}
newVal('male ','white ', 'christian ');
newVal('female','white ', 'christian ');
jsFiddle: https://jsfiddle.net/AndrewL64/p6rgo01a/1/
You, possibly asked wrong question, or, your original intentions are not reflected in question, but as far as I understand, you are looking for sth like that.
var races = ["caucasian", "ethiopian", "malayan", "american", "mongolian"];
var beliefs = ["jewish", "buddhist", "muslim", "christian", "shintoist"];
var genders = ["male", "female"];
var randomArrayElement = function(arr) {
return arr[Math.floor(Math.random() * arr.length)];
}
function makeCombo(r, b, g) {
var race = randomArrayElement(r);
var belief = randomArrayElement(b);
var gender = randomArrayElement(g);
return [race, belief, gender].join(" ");
}
document.querySelector("button").addEventListener("click", function(e){
document.getElementById("profile-area").innerText = makeCombo(races, beliefs, genders);
})
<p id='profile-area'></p>
<button>Generate a profile</button>
You should define a shuffle function. Something like this:
// define shuffle function
function shuffle(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
return arr;
}
Then you can call this function with chars as a param to create a shuffled array like this:
var chars = [gen, race, rel];
You can then output the result as a string like this:
document.getElementById("demo").innerHTML = shuffle(chars).join(" ");
The join(" ") to replace the comma with an space.
option 1) reshuffle with new value(s)
As your original chars array's order doesn't shuffle, you can change the value's by doing this:
chars[0] = "female";
You can update the DOM by calling the shuffle function again as shown above.
option 2) keep the shuffled order en output it with an updated value
To keep the shuffled order, but output the array again with an updated value, you need to store the shuffled output in a new variable. You will get something like this:
var chars = [gen, race, rel];
var shuffled = shuffle(chars);
document.getElementById("demo").innerHTML = shuffled;
// change value of gen
shuffled[shuffled.indexOf("male")] = "female";
// output again
document.getElementById("demo").innerHTML = shuffled;
Related
user_input = "";
answer = "";
Array.greeting = ["hi", "hello"]
Array.names = ["john","james"]
user_input = document.getElementById('user_input').value.toLowerCase();
document.getElementById('text_input').innerHTML = user_input;
documnet.getElementById('say_something').innerHTML = say;
if(""){}
else{}
if(Array.greeting.includes(user_input) > 0){
say = "Hello";
}
if(Array.names.includes(user_input) > 0){
say = "User";
}
This is what i understand and have got up and running with correct outputs but how could i use input "hi john" and get output of "Hello User" with out baking it into an array?
You could do it like this:
var greetings = ["hi", "hello"];
var names = ["john","james"];
submit.onclick = function () {
// Split input into words, and convert that array to a Set for fast lookup
var words = new Set(user_input.value.split(/\s+/));
// Choose a greeting that is not among the input words.
// If all of them occur in the input, take the first greeting word
var greeting = greetings.find( greeting => !words.has(greeting)) || greetings[0];
// Choose a name that is not among the input words (or take the first)
var name = names.find( name => !words.has(name)) || names[0];
// Output with textContent (not innerHTML!)
text_input.textContent = user_input.value;
say_something.textContent = greeting + ' ' + name;
}
Input: <input id="user_input"><button id="submit">Submit</button><br>
You said: <span id="text_input"></span><br>
Reply: <span id="say_something"></span>
Obviously, when you enter both "hi" and "hello", the code will not find a greeting to use. In that case it uses the first greeting in the array ("hi"). The same principle applies for the names.
Let's simplify your requirement as:
You want to check if any element of an array "arr" contains part of string "s".
var check = function(arr, s) {
for (var i = 0; i < arr.length; i++) {
if (s.indexOf(arr[i]) > -1) {
return true;
}
}
return false;
}
This question already has an answer here:
Math random to find Names in an Array while not duplicating
(1 answer)
Closed 1 year ago.
window.onload = start;
function start () {
var name = ["Hans","Ole","Nils","Olav","Per","Knut","Kari","Line","Pia"]
var random = Math.floor(Math.random()*8)
var random2 = Math.floor(Math.random()*8)
var random3 = Math.floor(Math.random()*8)
var name2 = []
name2.push(name[random])
name2.push(name[random2])
name2.push(name[random3])
for(i=0; i<3; i++) {
document.getElementById("par").innerHTML += name2[i] + "<br/>" ;
}
}
So far with this code i can generate 3 random names from the name array. But i want the 3 names not to be repeated, and I don't know how to make that happen.
Perhaps this could help. I randomized the order of the array and then just pick the first three elements. This allows for zero repeats of names and generating a new answer each time the function is ran. Not sure what your HTML looks like so I just added the id "demo".
var players = ["Hans","Ole","Nils","Olav","Per","Knut","Kari","Line","Pia"];
function tournament() {
var names = [];
players.sort(function(a,b){return 0.5 - Math.random()});
for (i=0; i<3; i++){
names.push(players[i]);
}
document.getElementById("demo").innerHTML = names;
}
I created a solution that uses recursion.
The function randomNames gets repeated three times. Each time it gets called count gets increased and names is an array without the names that are already taken. It returns an array that holds the three random names.
function start () {
var name = ["Hans","Ole","Nils","Olav","Per","Knut","Kari","Line","Pia"]
function randomNames(count, names) {
if(count >= 3) return [];
var random = Math.floor(Math.random()*(names.length-1));
// remove current name
var name = names.splice(random, 1);
return randomNames(++count, names).concat(name);
}
var random = randomNames(0, name);
}
You could use a hash table for the chosen items and check against until all wanted items are found.
window.onload = start;
function start() {
var name = ["Hans", "Ole", "Nils", "Olav", "Per", "Knut", "Kari", "Line", "Pia"],
hash = {},
random;
while (Object.keys(hash).length < 3) {
do {
random = Math.floor(Math.random() * name.length);
} while (hash[random])
hash[random] = true;
document.getElementById("par").innerHTML += name[random] + "<br/>";
}
}
<div id="par"></div>
ES6 with Set
window.onload = start;
function start() {
var name = ["Hans", "Ole", "Nils", "Olav", "Per", "Knut", "Kari", "Line", "Pia"],
hash = new Set,
random;
while (hash.size < 3) {
do {
random = Math.floor(Math.random() * name.length);
} while (hash.has(random))
hash.add(random);
document.getElementById("par").innerHTML += name[random] + "<br/>";
}
}
<div id="par"></div>
How can I implement javascript function to calculate frequency of each word in a given sentence.
this is my code:
function search () {
var data = document.getElementById('txt').value;
var temp = data;
var words = new Array();
words = temp.split(" ");
var uniqueWords = new Array();
var count = new Array();
for (var i = 0; i < words.length; i++) {
//var count=0;
var f = 0;
for (j = 0; j < uniqueWords.length; j++) {
if (words[i] == uniqueWords[j]) {
count[j] = count[j] + 1;
//uniqueWords[j]=words[i];
f = 1;
}
}
if (f == 0) {
count[i] = 1;
uniqueWords[i] = words[i];
}
console.log("count of " + uniqueWords[i] + " - " + count[i]);
}
}
am unable to trace out the problem ..any help is greatly appriciated.
output in this format:
count of is - 1
count of the - 2..
input: this is anil is kum the anil
Here is a JavaScript function to get the frequency of each word in a sentence:
function wordFreq(string) {
var words = string.replace(/[.]/g, '').split(/\s/);
var freqMap = {};
words.forEach(function(w) {
if (!freqMap[w]) {
freqMap[w] = 0;
}
freqMap[w] += 1;
});
return freqMap;
}
It will return a hash of word to word count. So for example, if we run it like so:
console.log(wordFreq("I am the big the big bull."));
> Object {I: 1, am: 1, the: 2, big: 2, bull: 1}
You can iterate over the words with Object.keys(result).sort().forEach(result) {...}. So we could hook that up like so:
var freq = wordFreq("I am the big the big bull.");
Object.keys(freq).sort().forEach(function(word) {
console.log("count of " + word + " is " + freq[word]);
});
Which would output:
count of I is 1
count of am is 1
count of big is 2
count of bull is 1
count of the is 2
JSFiddle: http://jsfiddle.net/ah6wsbs6/
And here is wordFreq function in ES6:
function wordFreq(string) {
return string.replace(/[.]/g, '')
.split(/\s/)
.reduce((map, word) =>
Object.assign(map, {
[word]: (map[word])
? map[word] + 1
: 1,
}),
{}
);
}
JSFiddle: http://jsfiddle.net/r1Lo79us/
I feel you have over-complicated things by having multiple arrays, strings, and engaging in frequent (and hard to follow) context-switching between loops, and nested loops.
Below is the approach I would encourage you to consider taking. I've inlined comments to explain each step along the way. If any of this is unclear, please let me know in the comments and I'll revisit to improve clarity.
(function () {
/* Below is a regular expression that finds alphanumeric characters
Next is a string that could easily be replaced with a reference to a form control
Lastly, we have an array that will hold any words matching our pattern */
var pattern = /\w+/g,
string = "I I am am am yes yes.",
matchedWords = string.match( pattern );
/* The Array.prototype.reduce method assists us in producing a single value from an
array. In this case, we're going to use it to output an object with results. */
var counts = matchedWords.reduce(function ( stats, word ) {
/* `stats` is the object that we'll be building up over time.
`word` is each individual entry in the `matchedWords` array */
if ( stats.hasOwnProperty( word ) ) {
/* `stats` already has an entry for the current `word`.
As a result, let's increment the count for that `word`. */
stats[ word ] = stats[ word ] + 1;
} else {
/* `stats` does not yet have an entry for the current `word`.
As a result, let's add a new entry, and set count to 1. */
stats[ word ] = 1;
}
/* Because we are building up `stats` over numerous iterations,
we need to return it for the next pass to modify it. */
return stats;
}, {} );
/* Now that `counts` has our object, we can log it. */
console.log( counts );
}());
const sentence = 'Hi my friend how are you my friend';
const countWords = (sentence) => {
const convertToObject = sentence.split(" ").map( (i, k) => {
return {
element: {
word: i,
nr: sentence.split(" ").filter(j => j === i).length + ' occurrence',
}
}
});
return Array.from(new Set(convertToObject.map(JSON.stringify))).map(JSON.parse)
};
console.log(countWords(sentence));
Here is an updated version of your own code...
<!DOCTYPE html>
<html>
<head>
<title>string frequency</title>
<style type="text/css">
#text{
width:250px;
}
</style>
</head>
<body >
<textarea id="txt" cols="25" rows="3" placeholder="add your text here"> </textarea></br>
<button type="button" onclick="search()">search</button>
<script >
function search()
{
var data=document.getElementById('txt').value;
var temp=data;
var words=new Array();
words=temp.split(" ");
var unique = {};
for (var i = 0; i < words.length; i++) {
var word = words[i];
console.log(word);
if (word in unique)
{
console.log("word found");
var count = unique[word];
count ++;
unique[word]=count;
}
else
{
console.log("word NOT found");
unique[word]=1;
}
}
console.log(unique);
}
</script>
</body>
I think your loop was overly complicated. Also, trying to produce the final count while still doing your first pass over the array of words is bound to fail because you can't test for uniqueness until you have checked each word in the array.
Instead of all your counters, I've used a Javascript object to work as an associative array, so we can store each unique word, and the count of how many times it occurs.
Then, once we exit the loop, we can see the final result.
Also, this solution uses no regex ;)
I'll also add that it's very hard to count words just based on spaces. In this code, "one, two, one" will results in "one," and "one" as being different, unique words.
While both of the answers here are correct maybe are better but none of them address OP's question (what is wrong with the his code).
The problem with OP's code is here:
if(f==0){
count[i]=1;
uniqueWords[i]=words[i];
}
On every new word (unique word) the code adds it to uniqueWords at index at which the word was in words. Hence there are gaps in uniqueWords array. This is the reason for some undefined values.
Try printing uniqueWords. It should give something like:
["this", "is", "anil", 4: "kum", 5: "the"]
Note there no element for index 3.
Also the printing of final count should be after processing all the words in the words array.
Here's corrected version:
function search()
{
var data=document.getElementById('txt').value;
var temp=data;
var words=new Array();
words=temp.split(" ");
var uniqueWords=new Array();
var count=new Array();
for (var i = 0; i < words.length; i++) {
//var count=0;
var f=0;
for(j=0;j<uniqueWords.length;j++){
if(words[i]==uniqueWords[j]){
count[j]=count[j]+1;
//uniqueWords[j]=words[i];
f=1;
}
}
if(f==0){
count[i]=1;
uniqueWords[i]=words[i];
}
}
for ( i = 0; i < uniqueWords.length; i++) {
if (typeof uniqueWords[i] !== 'undefined')
console.log("count of "+uniqueWords[i]+" - "+count[i]);
}
}
I have just moved the printing of count out of the processing loop into a new loop and added a if not undefined check.
Fiddle: https://jsfiddle.net/cdLgaq3a/
I had a similar assignment. This is what I did:
Assignment : Clean the following text and find the most frequent word (hint, use replace and regular expressions).
const sentence = '%I $am#% a %tea#cher%, &and& I lo%#ve %te#a#ching%;. The#re $is no#th#ing; &as& mo#re rewarding as educa#ting &and& #emp%o#weri#ng peo#ple. ;I found tea#ching m%o#re interesting tha#n any ot#her %jo#bs. %Do#es thi%s mo#tiv#ate yo#u to be a tea#cher!? %Th#is 30#Days&OfJavaScript &is al#so $the $resu#lt of &love& of tea&ching'
console.log(`\n\n 03.Clean the following text and find the most frequent word (hint, use replace and regular expressions) \n\n ${sentence} \n\n`)
console.log(`Cleared sentence : ${sentence.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()#]/g, "")}`)
console.log(mostFrequentWord(sentence))
function mostFrequentWord(sentence) {
sentence = sentence.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()#]/g, "").trim().toLowerCase()
let sentenceArray = sentence.split(" ")
let word = null
let count = 0
for (i = 0; i < sentenceArray.length; i++) {
word = sentenceArray[i]
count = sentence.match(RegExp(sentenceArray[i], 'gi')).length
if (count > count) {
count = count
word = word
}
}
return `\n Count of most frequent word "${word}" is ${count}`
}
I'd go with Sampson's match-reduce method for slightly better efficiency. Here's a modified version of it that is more production-ready. It's not perfect, but it should cover the vast majority of scenarios (i.e., "good enough").
function calcWordFreq(s) {
// Normalize
s = s.toLowerCase();
// Strip quotes and brackets
s = s.replace(/["“”(\[{}\])]|\B['‘]([^'’]+)['’]/g, '$1');
// Strip dashes and ellipses
s = s.replace(/[‒–—―…]|--|\.\.\./g, ' ');
// Strip punctuation marks
s = s.replace(/[!?;:.,]\B/g, '');
return s.match(/\S+/g).reduce(function(oFreq, sWord) {
if (oFreq.hasOwnProperty(sWord)) ++oFreq[sWord];
else oFreq[sWord] = 1;
return oFreq;
}, {});
}
calcWordFreq('A ‘bad’, “BAD” wolf-man...a good ol\' spook -- I\'m frightened!') returns
{
"a": 2
"bad": 2
"frightened": 1
"good": 1
"i'm": 1
"ol'": 1
"spook": 1
"wolf-man": 1
}
I have a string like this:
(apple,apple,orange,banana,strawberry,strawberry,strawberry). I want to count the number of occurrences for each of the characters, e.g. banana (1) apple(2) and strawberry(3). how can I do this?
The closest i could find was something like, which i dont know how to adapt for my needs:
function countOcurrences(str, value){
var regExp = new RegExp(value, "gi");
return str.match(regExp) ? str.match(regExp).length : 0;
}
Here is the easiest way to achieve that by using arrays.. without any expressions or stuff. Code is fairly simple and self explanatory along with comments:
var str = "apple,apple,orange,banana,strawberry,strawberry,strawberry";
var arr = str.split(','); //getting the array of all fruits
var counts = {}; //this array will contain count of each element at it's specific position, counts['apples']
arr.forEach(function(x) { counts[x] = (counts[x] || 0)+1; }); //checking and addition logic.. e.g. counts['apples']+1
alert("Apples: " + counts['apple']);
alert("Oranges: " + counts['orange']);
alert("Banana: " + counts['banana']);
alert("Strawberry: " + counts['strawberry']);
See the DEMO here
You can try
var wordCounts = str.split(",").reduce(function(result, word){
result[word] = (result[word] || 0) + 1;
return result;
}, {});
wordCounts will be a hash {"apple":2, "orange":1, ...}
You can print it as the format you like.
See the DEMO http://repl.it/YCO/10
You can use split also:
function getCount(str,d) {
return str.split(d).length - 1;
}
getCount("fat math cat", "at"); // return 3
I am trying to make a very basic "secret santa" generator as one of my first Javascript projects. I have searched for hours for a solution to this problem but so far nothing has worked that I have found.
I have an array of names which need paired to each other. I successfully have them pairing to each other, but right now someone can be drawn twice. I am pushing the randomly chosen names to another array but I can't find a way to check the randomly chosen names against the ones already chosen.
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
var used = [];
var picks = [];
if (names.length % 2 != 0) {
alert("You must have an even number of names. You currently have " + names.length + " names.");
}
for( var i = 0; i < names.length; i++){
var random = Math.floor(Math.random()*names.length)
if(names[random] == names[i]) {
names[random] = names[random++];
picks.push(names[i] + " gets " + names[random]);
used.push(names[random]);
} else {
picks.push(names[i] + " gets " + names[random]);
used.push(names[random]);
}
}
console.log("picked array: ")
for(var k=0; k<picks.length; k++) {
console.log(picks[k]);
}
console.log("used array: " + used);
Thank you in advance for any help.
Create two arrays with the names, shuffle them, and make sure you don't pick the same name from both arrays :
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
if (names.length % 2 != 0) {
alert("You must have an even number of names. You currently have " + names.length + " names.");
} else {
var arr1 = names.slice(), // copy array
arr2 = names.slice(); // copy array again
arr1.sort(function() { return 0.5 - Math.random();}); // shuffle arrays
arr2.sort(function() { return 0.5 - Math.random();});
while (arr1.length) {
var name1 = arr1.pop(), // get the last value of arr1
name2 = arr2[0] == name1 ? arr2.pop() : arr2.shift();
// ^^ if the first value is the same as name1,
// get the last value, otherwise get the first
console.log(name1 + ' gets ' + name2);
}
}
FIDDLE
I would suggest a different approach. Shuffle, split, and zip, no mutation:
var splitAt = function(i, xs) {
var a = xs.slice(0, i);
var b = xs.slice(i, xs.length);
return [a, b];
};
var shuffle = function(xs) {
return xs.slice(0).sort(function() {
return .5 - Math.random();
});
};
var zip = function(xs) {
return xs[0].map(function(_,i) {
return xs.map(function(x) {
return x[i];
});
});
}
// Obviously assumes even array
var result = zip(splitAt(names.length/2, shuffle(names)));
//^
// [
// [ 'Nick', 'Kimmy' ],
// [ 'Sean', 'Johnny' ],
// [ 'Kyle', 'Brian' ],
// [ 'Cotter', 'Pat' ],
// [ 'Emily', 'Jeremy' ]
// ]
There is a multitude of ways you can achieve this.
The fastest to code, but not necessarily the randomest is:
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
function getPicks(names) {
return names.slice(0).sort(function(){ return Math.random()-0.5 }).map(function(name, index, arr){
return name + " gets " + arr[(index+1)%arr.length];
});
}
getPicks(names);
This is not very random because the shuffling isn't very good and also because you get a single cycle each time. There can be no two cycles A->B->C->A D->E->D.
If you want it to have a random number of cycles of variable length, you can split the names array in several arrays and do the above for each of them, then concatenate the results (see elclanrs).
Finally, the last solution is for each person to pick a person at random and if it's the same one, simply pick again. If the last name remaining in both arrays is the same, simply swap it with another pair.
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
var a = names.slice(0);
var b = names.slice(0);
var result = [];
while (a.length > 1) {
var i = extractRandomElement(a);
var j = extractRandomElement(b);
while (i===j) {
b.push(j);
j = extractRandomElement(b);
}
result.push({ a:i, b:j });
}
if (a[0] === b[0]) {
result.push({ a:a[0], b:result[0].b });
result[0].b = a[0];
} else {
result.push({ a:a[0], b:b[0] });
}
var pairs = result.map(function(item){ return item.a + ' gets ' + item.b});
function extractRandomElement(array) {
return array.splice(Math.floor(Math.random()*array.length),1)[0];
}
I'm a tad late, but thought I'd throw my answer in here. It essentially does the same thing #adeneo's does, but it uses the same basic code as OP:
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
pickpool = names.slice(0); // Slice the array at the first element to copy it by value
var used = [];
var picks = [];
if (names.length % 2 != 0) {
alert("You must have an even number of names. You currently have " + names.length + " names.");
}
for( var i = 0; i < names.length; i++){
var random = Math.floor(Math.random()*pickpool.length)
if(names[random] == names[i]) {
// names[random] = names[random++];
picks.push(names[i] + " gets " + pickpool[random++]);
pickpool.splice(random++,1);
} else {
picks.push(names[i] + " gets " + pickpool[random]);
pickpool.splice(random,1);
}
}
console.log("picked array: ");
for(var k=0; k<picks.length; k++) {
console.log(picks[k]);
}
http://jsfiddle.net/SNJpC/
If you don't need to keep the original array you can remove the names as they get selected and each time you pick a name check that it isn't an empty string before pushing it to the next array.
Another consideration...
If you are trying to make a 'Secret Santa' generator, by using random method you can get the same pair next year, and next...
This is another solution where you get all the possible pairs (without repeating a name itself or a pair) for multiple years.
var names = ["Sean", "Kyle", "Emily", "Nick", "Cotter", "Brian", "Jeremy", "Kimmy", "Pat", "Johnny"];
if (names.length % 2 != 0) {
alert("You must have an even number of names. You currently have " + names.length + " names.");
} else {
const arr1 = names.slice()
let arr2 = names.slice();
let countDown = number => {
if (number === 1) {
return;
}
const last = arr2.pop([number - 1]);
arr2.unshift(last);
let pairs = [];
arr1.map(item => {
const index = arr1.indexOf(item);
pairs.push(`${arr1[index]} gets ${arr2[index]}`)
})
console.log(pairs)
return countDown(number - 1);
}
countDown(names.length)
}