My web app is taking in arbitrarily large 2D arrays that sometimes look something like this:
var multiArray = [["","","",""],[1,2,3],["hello","dog","cat"],["","","",""]];
I want to write a function to take out every array inside of multiArray that is comprised entirely of quotes. In other words, any array that looks like this:
["","","",""]
should be deleted from multiArray.
I tried writing the following function, but the problem with using splice in a for loop is that splicing will change the length of the array, and I end up trying to access undefined elements. Please help!
Thanks!
Here's the incorrect function I wrote:
function cleanWhitespace(arrayOfArrays) {
var i;
var arrayOfArraysLength = arrayOfArrays.length;
for (i = 0; i < arrayOfArraysLength; i++) {
var cleanedArray = $.grep(arrayOfArrays[i], function(element) {
return element != ""
});
if (cleanedArray.length == 0) {
arrayOfArrays.splice(i, 1);
}
}
return arrayOfArrays;
};
You can use $.grep :
multiArray = $.grep(multiArray, function(v){
return v.join('');
});
Fiddle : http://jsfiddle.net/scZcB/
on the fly:
var multiArray = [["","","",""],[1,2,3],["hello","dog","cat"],["","","",""]];
var outputArr = removeQuoteArrays(multiArray);
console.log(outputArr);
function removeQuoteArrays(arr) {
var outputArr = [];
for (var i = 0; i < arr.length; i++) {
var currArr = arr[i];
var isAllQuotes = true;
for (var j = 0; j < currArr.length; j++) {
if (currArr[j] != "") {
isAllQuotes = false;
break;
}
}
if (!isAllQuotes) {
outputArr.push(currArr);
}
}
return outputArr;
}
Here's a JSFiddle.
Create a new array instead.
// Only add if...
cleanedArray = multiArray.filter(function(arr){
// Some elements are not blank
return arr.some(function(e){ return e !== "" })
})
I added a length check to your function to break out of the loop if the index reaches the array length:
if (i >= arrayOfArrays.length)
break;
Which makes:
function cleanWhitespace(arrayOfArrays) {
var i;
var arrayOfArraysLength = arrayOfArrays.length;
for (i = 0; i < arrayOfArraysLength; i++) {
var cleanedArray = $.grep(arrayOfArrays[i], function(element) {
return element != ""
});
if (cleanedArray.length == 0) {
arrayOfArrays.splice(i, 1);
if (i >= arrayOfArrays.length)
break;
}
}
return arrayOfArrays;
};
var multiArray = [["","","",""],[1,2,3],["hello","dog","cat"],["","","",""]];
function cleanWhitespace(arrayOfArrays) {
for (var i = 0; i < arrayOfArrays.length; i++) {
var emptyElements = 0;
for (var j = 0; j < arrayOfArrays[i].length; j++ ) {
if (arrayOfArrays[i][j] === "") {
emptyElements++;
}
}
if (emptyElements === arrayOfArrays[i].length) {
arrayOfArrays.splice(i, 1);
}
}
return arrayOfArrays;
}
console.log(cleanWhitespace(multiArray));
http://jsfiddle.net/4Jfr9/
Related
Okay, so I've been working on a sort function for my application, and I've gotten stuck.
Here's my fiddle.
To explain briefly, this code starts with an array of strings, serials, and an empty array, displaySerials:
var serials = ["BHU-009", "BHU-008", "BHU-001", "BHU-010", "BHU-002", "TYU-970", "BHU-011", "TYU-969", "BHU-000"];
var displaySerials = [];
The aim of these functions is to output displaySerials as an array of objects with two properties: beginSerial and endSerial. The way that this is intended to work is that the function loops through the array, and tries to set each compatible string in a range with each other, and then from that range create the object where beginSerial is the lowest serial number in range and endSerial is the highest in range.
To clarify, all serials in a contiguous range will have the same prefix. Once that prefix is established then the strings are broken apart from the prefix and compared and sorted numerically.
So based on that, the desired output from the array serials would be:
displaySerials = [
{ beginSerial: "BHU-008", endSerial: "BHU-011" },
{ beginSerial: "BHU-000", endSerial: "BHU-002" },
{ beginSerial: "TYU-969", endSerial: "TYU-970" }
]
I've got it mostly working on my jsfiddle, the only problem is that the function is pushing one duplicate object into the array, and I'm not sure how it is managing to pass my checks.
Any help would be greatly appreciated.
Marc's solution is correct, but I couldn't help thinking it was too much code. This is doing exactly the same thing, starting with sort(), but then using reduce() for a more elegant look.
var serials = ["BHU-009", "BHU-008", "BHU-001", "BHU-010", "BHU-002", "TYU-970", "BHU-011", "TYU-969", "BHU-000"]
serials.sort()
var first = serials.shift()
var ranges = [{begin: first, end: first}]
serials.reduce(mergeRange, ranges[0])
console.log(ranges) // the expected result
// and this is the reduce callback:
function mergeRange(lastRange, s)
{
var parts = s.split(/-/)
var lastParts = lastRange.end.split(/-/)
if (parts[0] === lastParts[0] && parts[1]-1 === +lastParts[1]) {
lastRange.end = s
return lastRange
} else {
var newRange = {begin: s, end: s}
ranges.push(newRange)
return newRange
}
}
I've got a feeling that it's possible to do it without sorting, by recursively merging the results obtained over small pieces of the array (compare elements two by two, then merge results two by two, and so on until you have a single result array). The code wouldn't look terribly nice, but it would scale better and could be done in parallel.
Nothing too sophisticated here, but it should do the trick. Note that I'm sorting the array from the get-go so I can reliably iterate over it.
Fiddle is here: http://jsfiddle.net/qyys9vw1/
var serials = ["BHU-009", "BHU-008", "BHU-001", "BHU-010", "BHU-002", "TYU-970", "BHU-011", "TYU-969", "BHU-000"];
var myNewObjectArray = [];
var sortedSerials = serials.sort();
//seed the object
var myObject = {};
var previous = sortedSerials[0];
var previousPrefix = previous.split("-")[0];
var previousValue = previous.split("-")[1];
myObject.beginSerial = previous;
myObject.endSerial = previous;
//iterate watching for breaks in the sequence
for (var i=1; i < sortedSerials.length; i++) {
var current = sortedSerials[i];
console.log(current);
var currentPrefix = current.split("-")[0];
var currentValue = current.split("-")[1];
if (currentPrefix === previousPrefix && parseInt(currentValue) === parseInt(previousValue)+1) {
//sequential value found, so update the endSerial with it
myObject.endSerial = current;
previous = current;
previousPrefix = currentPrefix;
previousValue = currentValue;
} else {
//sequence broken; push the object
console.log(currentPrefix, previousPrefix, parseInt(currentValue), parseInt(previousValue)+1);
myNewObjectArray.push(myObject);
//re-seed a new object
previous = current;
previousPrefix = currentPrefix;
previousValue = currentValue;
myObject = {};
myObject.beginSerial = current;
myObject.endSerial = current;
}
}
myNewObjectArray.push(myObject); //one final push
console.log(myNewObjectArray);
I would use underscore.js for this
var bSerialExists = _.findWhere(displaySerials, { beginSerial: displaySettings.beginSerial });
var eSerialExists = _.findWhere(displaySerials, { endSerial: displaySettings.endSerial });
if (!bSerialExists && !eSerialExists)
displaySerials.push(displaySettings);
I ended up solving my own problem because I was much closer than I thought I was. I included a final sort to get rid of duplicate objects after the initial sort was finished.
var serials = ["BHU-009", "BHU-008", "BHU-001", "BHU-010", "BHU-002", "TYU-970", "BHU-011", "TYU-969", "BHU-000"];
var displaySerials = [];
var mapSerialsForDisplay = function () {
var tempArray = serials;
displaySerials = [];
for (var i = 0; i < tempArray.length; i++) {
// compare current member to all other members for similarity
var currentSerial = tempArray[i];
var range = [currentSerial];
var displaySettings = {
beginSerial: currentSerial,
endSerial: ""
}
for (var j = 0; j < tempArray.length; j++) {
if (i === j) {
continue;
} else {
var stringInCommon = "";
var comparingSerial = tempArray[j];
for (var n = 0; n < currentSerial.length; n++) {
if (currentSerial[n] === comparingSerial[n]) {
stringInCommon += currentSerial[n];
continue;
} else {
var currentRemaining = currentSerial.replace(stringInCommon, "");
var comparingRemaining = comparingSerial.replace(stringInCommon, "");
if (!isNaN(currentRemaining) && !isNaN(comparingRemaining) && stringInCommon !== "") {
range = compareAndAddToRange(comparingSerial, stringInCommon, range);
displaySettings.beginSerial = range[0];
displaySettings.endSerial = range[range.length - 1];
var existsAlready = false;
for (var l = 0; l < displaySerials.length; l++) {
if (displaySerials[l].beginSerial == displaySettings.beginSerial || displaySerials[l].endSerial == displaySettings.endSerial) {
existsAlready = true;
}
}
if (!existsAlready) {
displaySerials.push(displaySettings);
}
}
}
}
}
}
}
for (var i = 0; i < displaySerials.length; i++) {
for (var j = 0; j < displaySerials.length; j++) {
if (i === j) {
continue;
} else {
if (displaySerials[i].beginSerial === displaySerials[j].beginSerial && displaySerials[i].endSerial === displaySerials[j].endSerial) {
displaySerials.splice(j, 1);
}
}
}
}
return displaySerials;
}
var compareAndAddToRange = function (candidate, commonString, arr) {
var tempArray = [];
for (var i = 0; i < arr.length; i++) {
tempArray.push({
value: arr[i],
number: parseInt(arr[i].replace(commonString, ""))
});
}
tempArray.sort(function(a, b) {
return (a.number > b.number) ? 1 : ((b.number > a.number) ? -1 : 0);
});
var newSerial = {
value: candidate,
number: candidate.replace(commonString, "")
}
if (tempArray.indexOf(newSerial) === -1) {
if (tempArray[0].number - newSerial.number === 1) {
tempArray.unshift(newSerial)
} else if (newSerial.number - tempArray[tempArray.length - 1].number === 1) {
tempArray.push(newSerial);
}
}
for (var i = 0; i < tempArray.length; i++) {
arr[i] = tempArray[i].value;
}
arr.sort();
return arr;
}
mapSerialsForDisplay();
console.log(displaySerials);
fiddle to see it work
Here's a function that does this in plain JavaScript.
var serials = ["BHU-009", "BHU-008", "BHU-001", "BHU-010", "BHU-002", "TYU-970", "BHU-011", "TYU-969", "BHU-000"];
function transformSerials(a) {
var result = []; //store array for result
var holder = {}; //create a temporary object
//loop the input array and group by prefix
a.forEach(function(val) {
var parts = val.split('-');
var type = parts[0];
var int = parseInt(parts[1], 10);
if (!holder[type])
holder[type] = { prefix : type, values : [] };
holder[type].values.push({ name : val, value : int });
});
//interate through the temp object and find continuous values
for(var type in holder) {
var last = null;
var groupHolder = {};
//sort the values by integer
var numbers = holder[type].values.sort(function(a,b) {
return parseInt(a.value, 10) > parseInt(b.value, 10);
});
numbers.forEach(function(value, index) {
if (!groupHolder.beginSerial)
groupHolder.beginSerial = value.name;
if (!last || value.value === last + 1) {
last = value.value;
groupHolder.endSerial = value.name;
if (index === numbers.length - 1) {
result.push(groupHolder);
}
}
else {
result.push(groupHolder);
groupHolder = {};
last = null;
}
});
}
return result;
}
console.log(transformSerials(serials));
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
This is my code so far; All I've done is loop through each letter.
I'm stuck on how to test whether or not the strings have the same characters.
function mutation(arr) {
for (var i=0;i<arr.length;i++){
for(var j =0;j<arr[i].length;j++){
}
}
}
mutation(['hello', 'hey']);
The characters don't have to be at the same index, so for example, ['Alien', 'line'], should return true.
I used the answer above but modified it to remove the case, otherwise i was getting a false on Hello and hello
function mutation(arr) {
//first split the arr into the two inputs and convert all to lower case
var firstArray = arr[0].toLowerCase().split("");
var secondArray = arr[1].toLowerCase().split("");
//now using the code provided by the above comment which is really clean
var count = 0;
for (var i =0; i < secondArray.length; i++) {
if(firstArray.indexOf(secondArray[i]) > -1 ) {
count++;
}
}
if (count == secondArray.length) {
return true
}
//changed the code provided above to handle the true/false criteria of the excercise
else {return false; }
}
mutation(['hello', 'hey']);
You only have to loop once, and compare the second array against the first.
function mutation(arr) {
var arr1 = arr[0].split('');
var arr2 = arr[1].split('');
var count = 0;
for (var i =0; i < arr2.length; i++) {
if(arr1.indexOf(arr2[i]) > -1 ) {
count++;
}
}
if (count == arr2.length) {
console.log('all in');
}
}
mutation(['alien', 'line']);
Or you could use filter:
function mutation(arr) {
var arr1 = arr[0].split('');
var arr2 = arr[1].split('');
if (arr2.filter(function(element, index) { return arr1.indexOf(element); }).length === arr2.length) {
console.log('all in');
}
}
mutation(['alien', 'line']);
The counter in the accepted answer is unnecessary.
function mutation(arr) {
var arr1 = arr[0].toLowerCase().split('');
var arr2 = arr[1].toLowerCase().split('');
for (var i=0; i < arr2.length; i++) {
if(arr1.indexOf(arr2[i]) == -1 ) {
return false;
}
}
return true;
}
mutation(["hello", "hey"]);
Clean, modern and easy to read:
function mutation(arr) {
const firstEl = arr[0].toLocaleLowerCase();
const secondEl = arr[1].toLocaleLowerCase().split('');
return secondEl.every(el => firstEl.includes(el));
}
console.log('mutation(["hello", "hey"]): ', mutation(["hello", "hey"]));
console.log('mutation(["Alien", "line"]): ', mutation(["Alien", "line"]));
How about something cleaner? Just a little modification to an above code.
function mutation(arr) {
var first = arr[0].toLowerCase().split('');
var second = arr[1].toLowerCase().split('');
var count = 0;
// Check every character and if the index is found add one
for (var s in second){
if (first.indexOf(second[s]) > -1) {
count+= 0;
} else
count++;
}
if (count === 0)
return true;
else
return false;
}
even lesser code for this problem
function mutation(arr) {
var arr1 = arr[0].toLowerCase().split('');
var arr2 = arr[1].toLowerCase().split('');
for(var i of arr2)
if(arr1.indexOf(i)===-1)
return false;
return true;
}
mutation(["hello", "hey"]);
the code above will not work in all cases
because if the first word in array is shorter than second one you need second for loop
for (var i=0; i<arr1.length; i++){
if (arr2.indexOf(arr1[i])==-1){
return false;
you need 2 for loops
function mutation(arr) {
var arr1=arr[0].toLowerCase().split("");
var arr2=arr[1].toLowerCase().split("");
if (arr1.length<arr2.length ){
for (var i=0; i<arr1.length; i++){
if (arr2.indexOf(arr1[i])==-1){
return false;
}
}
}
else if (arr1.length>=arr2.length ){
for (var j=0; j<arr2.length; j++){
if (arr1.indexOf(arr2[j])==-1){
return false;
}
}
}
return true;
}
//mutation(["zyxwvutsrqponmlkjihgfedcba", "qrstu"]);
mutation([ "qrstu", "zyxwvutsrqponmlkjihgfedcba"]);
enter code here
I create an array like so
var membersList = $('#chatbox_members' , avacweb_chat.doc.body).find('li');
var onlineUsers = [];
var offLineUsers = [];
for(var i =0;i<membersList.length;i++){
var name = $(membersList[i]).text().replace("#","");
onlineUsers.push(name);
}
alert(onlineUsers);
listedUsers would come out something like so [Mr.EasyBB,Tonight,Tomorrow,Gone];
Question is if I use a two for loops one outside a setInterval and one inside to compare-
var membersList = $('#chatbox_members' , _chat.doc.body).find('li');
var onlineUsers = [];
var offLineUsers= [];
for(var i =0;i<membersList.length;i++){
var name = $(membersList[i]).text().replace("#","");
onlineUsers.push(name);
}
var int = setInterval(function() {
var newMember = ('#chatbox_members' , _chat.doc.body).find('li');
for(var i =0;i<newMember.length;i++){
var name = $(newMember[i]).text().replace("#","");
offLineUsers.push(name);
}
Which then would get:
onlineUsers = [Mr.EasyBB,Tonight,Tomorrow,Gone];
offLineUsers = [Mr.EasyBB,Tonight];
So to get the offline users I want to basically replace onlineUsers with offLineUsers which then should return Tomorrow,Gone . Though I know that an object doesn't have the function to replace so how would I go about this?
I don't think the splice function would work since you need to have parameters, and pop or shift are beginning and end of array.
for(var i = 0 ; i < offLineUsers.length ; i++)
{
for(var j = 0 ; j < onlineUsers.length ; j++)
{
if(onlineUsers[j] == offLineUsers[i])
{
onlineUsers.splice(j,1);
}
}
}
Try this snippet.
If I have understand well, maybe that helps:
function bus_dup() {
for(var i = 0; i < offLineUsers.length; i++) {
onLineUsers.splice(onLineUsers.indexOf(offLineUsers[i]),1);
}
offLineUsers = [];
}
This should do what you are looking for on a modern browser, using array.filter
var onlineUsers = ["Mr.EasyBB", "Tonight", "Tomorrow", "Gone"];
var offLineUsers = ["Mr.EasyBB", "Tonight"];
function discord(online, offline) {
return online.filter(function (element) {
return offline.indexOf(element) === -1;
});
}
console.log(discord(onlineUsers, offLineUsers));
Output
["Tomorrow", "Gone"]
On jsfiddle
If you want the difference regardless of the order of attributes passed to the function then you could do this.
var onlineUsers = ["Mr.EasyBB", "Tonight", "Tomorrow", "Gone"];
var offLineUsers = ["Mr.EasyBB", "Tonight"];
function difference(array1, array2) {
var a = array1.filter(function (element) {
return array2.indexOf(element) === -1;
});
var b = array2.filter(function (element) {
return array1.indexOf(element) === -1;
});
return a.concat(b);
}
console.log(difference(onlineUsers, offLineUsers));
console.log(difference(offLineUsers, onlineUsers));
Output
["Tomorrow", "Gone"]
["Tomorrow", "Gone"]
On jsfiddle
I'd like to split a string ("1,2,3") and return it as an int array so I wrote the following function:
function stringToIntArray(string) {
var split = {};
split = string.split(',');
var selected = {};
for (var i = 0; i <= split.length; i++) {
selected[i] = split[i];
}
return selected;
}
However split.length is always undefinied. Where's my mistake?
var selected = {};
doesn't build an array but an object, which has no length property.
You can fix your code by replacing it with
var selected = [];
If you want to return an array of numbers, you can change your code to
function stringToIntArray(string) {
var split = string.split(',');
var selected = [];
for (var i = 0; i < split.length; i++) {
selected.push(parseInt(split[i], 10));
}
return selected;
}
Note that I replaced <= with < in your loop.
Note also that for modern browsers, you can use the map function to make it simpler :
function stringToIntArray(string) {
return string.split(',').map(function(v){ return parseInt(v, 10) });
}
In my code I need to find the repeated value and give an alert using jQuery. Below is the example arrays and my requirement. Please help.
a1 = {1,2,3,4,5,6,4}
a2= {9,8,7},
a3= {a,b,c,d,e,7}
In the above arrays I need to get the value 4 and give alert because it is repeating in array "a1" and I need to get the value 7 because it is repeating in the arrays 'a2' and 'a3'.
The first issue I fixed like as follows. Ineed to to fix the second one.
for (var $i = 0; $i<= $last; $i++)
{
var hours = [];
var minutes = [];
var activeTime = [];
$.each($('.hour'+$i),function() {
hours.push($(this).val());
});
$.each($('.hour'+$i).next('select'),function(){
minutes.push($(this).val());
});
for ( var i = 0; i < hours.length; i++ ) {
activeTime.push(hours[ i ]+":"+minutes[ i ]+":"+"00");
}
for ( var i = 0; i <= hours.length; i++ ) {
if ( hours[ i ] === "" )
{
$("#timeValidate"+$i).css("display", "block");
return false;
}
else
{
$("#timeValidate"+$i).css("display", "none");
}
}
for(var i=0; i< activeTime.length; i++)
{
for(var j = 0; j< activeTime.length; j++)
{
if( i != j)
{
if(activeTime[j] == activeTime[i])
{
$("#timeValidate"+$i).text("");
$("#timeValidate"+$i).text("active time"+activeTime[j]+" is repeating");
$("#timeValidate"+$i).css("display", "block");
return false;
}
}
}
}
}
function getDuplicatesFromArrays() {
var allItems = Array.prototype.concat.apply([], arguments);
var duplicates = [];
var hash = {};
allItems.forEach(function(x) {
if(hash.hasOwnProperty(x)) duplicates.push(x);
hash[x] = 1;
});
return duplicates;
}
The above function accepts any number of arrays, and yields the duplicates:
getDuplicatesFromArrays(a1,a2,a3) // [4, 7]
Demo
It works as sort of an inverse hash sieve; adding to duplicates only if the item was already in the hash.
Try sugar.js, it has advanced functions for arrays (and others). For example, you can use a combination of unique() and subtract() to get an array that contains only the elements that are repeated. Then you can parse it and alert for each one.
Here you go:
var original = [].concat(a,b,c),
dupes = [];
for (var c = 0; c < original.length; c++) {
if (original.filter(function(v) {
return v == original[c];
}).length > 1) {
dupes.push(original[c]);
}
}
alert($.grep(dupes, function(v, k){return $.inArray(v , dupes) === k;}));
Here is a demo: http://jsfiddle.net/q2c42/