My function to remove duplicates is not working, any suggestions? - javascript

<p id="demo"></p>
<script>
//This is the email list
var emailList =["adam#yahoo.edu\n", "henry#yahoo.edu\n", "john#yahoo.edu\n", "sally#yahoo.edu\n", "adam#yahoo.edu\n", "david#yahoo.edu\n", "myhome#yahoo.edu\n", "david#yahoo.edu\n", "david#yahoo.edu\n", "hunger#yahoo.edu\n", "madison#yahoo.edu\n", ];
//I am removing #yahoo.edu
function removeAddress(list){
for (var i = 0; i < list.length; i++) {
list[i] = list[i].replace("#yahoo.edu", " ");
}
}
//Function to remove the duplicates in the list
function removeDuplicates(list)
{
var hash = {};
for (var i = 0; i < list.length; i++)
{
var array = list[i];
for (var j = 0; j < array.length; j++)
{
var val = array[j];
var hashedVal = hash[val];
if (hashedVal === undefined)
{
hash[val] = true;
}
else
{
array.splice(j, 1);
if (array.length == 0)
{
list.splice(i, 1);
}
}
}
}
}
document.getElementById("demo").innerHTML = emailList;
//Remove #yahoo.edu from the list
removeAddress(emailList);
//Sort the list
emailList.sort();
//Remove the duplicates
removeDuplicates(emailList);
//Print the list
document.getElementById("demo").innerHTML = emailList;
</script>
</body>
</html>

First of all, I'm not sure why you're traversing a 1 dimensional array with 2 loops. That's not necessary. Secondly, you're iterating through the array while also removing elements. When the element is removed, all elements after it are pushed forwards 1 index. Then i is incremented, causing you to miss an item. If you want to continue with the for loop and using .splice(), you need to manually decrement i when you remove an item. Also, you only need one loop since emailList is an array of strings.
function removeDuplicates(list)
{
var hash = {};
var newList = [];
for (var i = 0; i < list.length; i++)
{
var email = list[i];
if (hash[email] === undefined) {
hash[email] = true;
} else {
list.splice(i, 1);
i --;
}
}
}
See http://codepen.io/anon/pen/YyKJOP

In the inner for, you are looping a string, not another array.
Second, you may want to .join() the array at the end to obtain a printable string.

So essentially, you're just getting a list of user names. It could have been simplified to the following:
var emailList = ["adam#yahoo.edu\n", "henry#yahoo.edu\n", "john#yahoo.edu\n", "sally#yahoo.edu\n", "adam#yahoo.edu\n", "david#yahoo.edu\n", "myhome#yahoo.edu\n", "david#yahoo.edu\n", "david#yahoo.edu\n", "hunger#yahoo.edu\n", "madison#yahoo.edu\n"];
var usernameHash = emailList.reduce(function(usernames, email, i) {
var username = email.slice(0, email.indexOf('#'));
if(!usernames[username]) usernames[username] = true;
return usernames;
}, {});
var usernames = Object.keys(usernameHash)
document.write(usernames.join(', '));

Related

Function to check if parameter is still the same

I have a loop that has a function inside. my target here is to check if the current data inside the loop are still the same for example my array is like this
var data = ['test1','test1','test1','test2'];
now I will check them if the data on that array inside the loop are currently the same. for example like this.
for (var i = 0; i < data.length; i++) {
var value = data[i][0];
console.log(checkifcurrent(value));
}
my problem here is to return checkifcurrent(value) if it still the same like this
function checkifcurrent(value) {
if (currentvalue is still the same as the last one) {
console.log(same);
} else {
console.log(not same);
}
}
I hope you understand tysm for understanding
You can do it like this, no need for a function call.
var data = ['test1','test1','test1','test2'];
lastValue = data[0];
for (var i = 1; i < data.length; i++) {
var currentValue = data[i];
if(lastValue==currentValue){
console.log("Value is same")
}
else
{
console.log("Value is not same")
}
lastValue = currentValue;
}
you can iterate over the data array and compare with all the array elements except the one at the current position.
If it is equals to the current and the index is not the same of the current then it is a duplicate
var data = ['test1','test1','test1','test2'];
for (var i = 0; i < data.length; i++) {
var value = data[i];
for(var j = 0; j < data.length; j++){
//skip the index at position i, because it is the one we are currently comparing
if(i !== j && data[j] === value) {
console.log('another value like: ' + value + ' at position: ' + i + ' has been found at index: ' + j)
}
}
}
Its not very clear about your task, i hope it is checking if the a value present in arr1 is available are not in arr2. If you so,
Loop through all elements in arr1 and check the indexof it
arr1 =[1,2,3,4];
arr2 = [2,3,4,5,6,6];
arr1.forEach((x)=>{if(arr2.indexOf(x)==-1){console.log('unable to find the element'+x)}})
unable to find the element1
var isSame = (function () {
var previous;
return function(value){
var result = value === previous;
previous = value;
return result;
}
})();
Alternatively you can use lodash difference function to compare old and new array.
http://devdocs.io/lodash~4/index#difference
For example:
const _ = require('lodash')
// Save the old array somewhere
let oldArray = ['test1','test1','test1','test2']
let newArray = ['test1','test1','test1','test3']
const areParametersTheSame = !!(_.difference(oldArray, newArray))

Sort array of strings into array of objects

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>

removing multiple arrays from a 2D array

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/

How to show a list or array into a tree structure in javascript?

I pass this list from python to javascript like this:
var string=["test_data/new_directory/ok.txt","test_data/reads_1.fq","test_data/test_ref.fa"];
I want output like this:
test_data
reads_1.fq
test_ref.fa
new_directory
ok.txt
Or also the output could be like this:
test_data
reads_1.fq
test_ref.fa
test_data/new_directory
ok.txt
I used split function to get a list with each file and directory like this:
var string=["test_data/new_directory/ok.txt","test_data/reads_1.fq","test_data/test_ref.fa"];
for(var i=0;i<string.length;i++){
var result = string[i].split('/');
console.log(result);
}
Output looks like this:
["test_data", "new_directory", "ok.txt"]
["test_data", "reads_1.fq"]
["test_data", "test_ref.fa"]
How can I convert into the format I showed above? Thanks
Sorry for being late to the party. I ran into a similar issue trying to break out a list of paths into a nested object. Here's a fiddle showing how I ended up doing it.
var list = [];
list.push("A/B/C");
list.push("A/B/D");
list.push("A/B/C");
list.push("B/D/E");
list.push("D/B/E");
list.push("A/D/C");
var data = [];
for(var i = 0 ; i< list.length; i++)
{
buildTree(list[i].split('/'),data);
}
debugger;
function buildTree(parts,treeNode) {
if(parts.length === 0)
{
return;
}
for(var i = 0 ; i < treeNode.length; i++)
{
if(parts[0] == treeNode[i].text)
{
buildTree(parts.splice(1,parts.length),treeNode[i].children);
return;
}
}
var newNode = {'text': parts[0] ,'children':[]};
treeNode.push(newNode);
buildTree(parts.splice(1,parts.length),newNode.children);
}
https://jsfiddle.net/z07q8omt/
That's certainly possible, but it requires recursion.
The first thing you'll want to do (as you've already figured out to do, in fact) is split on the slashes. We'll use map for simplicity:
paths = paths.map(function(path) { return path.split('/'); });
Now we'll want to convert this into an array of objects with name and children properties. This means we'll have to use recursion.
In this function, we'll do a first pass grouping them by their first element:
var items = [];
for(var i = 0, l = paths.length; i < l; i++) {
var path = paths[i];
var name = path[0];
var rest = path.slice(1);
var item = null;
for(var j = 0, m = items.length; j < m; j++) {
if(items[j].name === name) {
item = items[j];
break;
}
}
if(item === null) {
item = {name: name, children: []};
items.push(item);
}
if(rest.length > 0) {
item.children.push(rest);
}
}
Then we can recurse on all of these (assuming the function name we chose was structurize):
for(i = 0, l = items.length; i < l; i++) {
item = items[i];
item.children = structurize(item.children);
}
Now we've got a nice structure. We can then stringify it, again with a recursive function. Since the directory listing is just each item name followed by the indented directory contents listing, we can write that fairly easily:
function stringify(items) {
var lines = [];
for(var i = 0, l = items.length; i < l; i++) {
var item = items[i];
lines.push(item.name);
var subLines = stringify(item.children);
for(var j = 0, m = subLines.length; j < m; j++) {
lines.push(" " + subLines[j]);
}
}
return lines;
}
Then, to actually do it:
console.log(stringify(structurize(paths)).join("\n"));

Array length undefined after split

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) });
}

Categories