我如何编写一个比较两个字符串的函数,并返回一个包含两个字符串中出现的字符的对象,以及它们出现的次数?
以下是一些示例输入和输出:
"Leopard", "Lion" // { "L": 2, "o": 2 }
"Hello", "World" // { "l": 3, "o": 2 }
"Flower", "Power" // { "o": 2, "w": 2, "e": 2, "r": 2 }
"phone", "Memphis" // { "p": 2, "h": 2, "e": 2 }
答案 0 :(得分:5)
如果您正在处理小字符串,则无需复杂化。以下方法很简单,在处理非常大的字符串时会牺牲性能。
首先,我们需要定义一个对象来保存重复字符的计数。
然后我们需要迭代每个字符串。迭代字符串有很多方法,但在下面的例子中我要么:
Array#forEach
方法(ES5示例)在字符串上调用Function#call
,或for...of
循环(ES6示例)。 这两种方法都有效,因为字符串是内置可迭代对象的一个示例。
在迭代字符串时,我们需要首先检查重复对象中是否存在该字符。
使用此方法,您不会计算不重复的字符,也不会尝试验证已经验证过的字符。这可以通过更长的字符串提供一些显着的速度提升。
完成两个字符串的迭代后,只需返回重复的持有者对象。
const countLetters = (v1, v2) => {
const out = {};
for(let char of v1) (out[char] || v2.indexOf(char) !== -1) && (out[char] = (out[char] || 0) + 1);
for(let char of v2) (out[char] || v1.indexOf(char) !== -1) && (out[char] = (out[char] || 0) + 1);
return out;
}
const test = (v1,v2) => (console.log(JSON.stringify(countLetters(v1, v2))),test);
test("Leopard", "Lion") // { "L": 2, "o": 2 }
("Hello", "World") // { "l": 3, "o": 2 }
("Flower", "Power") // { "o": 2, "w": 2, "e": 2, "r": 2 }
("phone", "Memphis") // { "p": 2, "h": 2, "e": 2 }
("Bookkeeper", "Zookeeper") // { "o": 4, "k": 3, "e": 6, "p": 2, "r": 2 }
("Some thing", "Other thing"); // { "e": 2, " ": 2, "t": 3, "h": 3, "i": 2, "n": 2, "g": 2 }
var countLetters = function(v1, v2) {
var out = {};
Array.prototype.forEach.call(v1, function(char) {
if(out[char] || v2.indexOf(char) !== -1) out[char] = (out[char] || 0) + 1;
});
Array.prototype.forEach.call(v2, function(char) {
if(out[char] || v1.indexOf(char) !== -1) out[char] = (out[char] || 0) + 1;
});
return out;
}
var test = function(v1,v2){ return (console.log(JSON.stringify(countLetters(v1, v2))),test) };
test("Leopard", "Lion") // { "L": 2, "o": 2 }
("Hello", "World") // { "l": 3, "o": 2 }
("Flower", "Power") // { "o": 2, "w": 2, "e": 2, "r": 2 }
("phone", "Memphis") // { "p": 2, "h": 2, "e": 2 }
("Bookkeeper", "Zookeeper") // { "o": 4, "k": 3, "e": 6, "p": 2, "r": 2 }
("Some thing", "Other thing"); // { "e": 2, " ": 2, "t": 3, "h": 3, "i": 2, "n": 2, "g": 2 }
当您开始使用非常大的字符串时,性能会成为一个问题。以下方法使用一些算法魔法来获得性能。
首先,找到两个字符串中每个字母的频率。 Working with a sorted array is faster than working with an unsorted array,并节省一些时间,因为我们可以将字符串拆分为常见字符组,而不是计算每个字符。
我使用Map
对象在下一个函数中利用Map#has
方法 - 比Array#indexOf
快得多。
// Calculate the frequency of each character in a string
const calculateCharacterFrequency = string => {
// Split the string into individual characters
const array = [...string];
// Sort the split string
const sorted = array.sort();
// Join the split string
const joined = sorted.join("");
// Split the string into groups of common characters
const matches = joined.match(/(.)\1*/g);
// Iterate the groups
const frequency = matches.reduce(
(frequency, character) => {
// Insert char and frequency into map
frequency.set(character[0], character.length);
// return frequency map for use in next iteration
return frequency;
},
// This is the map that will be passed as `frequency`
new Map()
);
// Return the map
return frequency;
};
接下来,找到每个字符串之间的常用字符,并创建一个包含每个常用字符频率的映射。
这里最大的性能提升是创建一个独特的字符集中出现的所有字符集。我利用Set
对象的独特性来从数组中删除重复项,还有其他方法可以从数组中删除重复项,但这是我测试过的最快的重复项。这样,我们只迭代一个unqiue集并检查字符是否出现在两个映射中。
// Calculate the frequency of each character two strings have in common
const calculateCommonCharacterFrequency = (v1, v2) => {
// Get frequency map of first string
v1 = calculateCharacterFrequency(v1);
// Get frequency map of second string
v2 = calculateCharacterFrequency(v2);
// Create an array containing a list of all characters occuring in either string
const combinedCharacterArray = [...v1.keys(), ...v2.keys()];
// Remove duplicate characters
const combinedUniqueCharacterSet = new Set(combinedCharacters);
// Convert set back to array
const combinedUniqueCharacterArray = Array.from(combinedUniqueSet);
// Iterate the unique array of common characters
const commonFrequency = combinedUniqueCharacterArray.reduce(
(commonFrequency, character) => {
// Check if both strings have the character
const isCommon = v1.has(character) && v2.has(character);
if(isCommon) {
// Find the sum of the frequency of the character in both strings
const combinedFrequency = v1.get(character) + v2.get(character);
// Insert character and frequency into map
commonFrequency.set(character, combinedFrequency);
}
// return frequency map for use in next iteration
return commonFrequency;
},
// This is the map that will be passed as `commonFrequency`
new Map()
);
// Return the map
return commonFrequency;
};
为了便于阅读和解释,上面的例子已经扩展。以下示例已经过浓缩以节省空间。
const calcCharFreq = string => [...string].sort().join("").match(/(.)\1*/g).reduce((freq, char) => (freq.set(char[0], char.length), freq), new Map());
const calcCommonCharFreq = (v1, v2) => {
v1 = calcCharFreq(v1);
v2 = calcCharFreq(v2);
return Array.from(new Set([...v1.keys(), ...v2.keys()])).reduce((dup, char) => ((v1.has(char) && v2.has(char)) && dup.set(char, v1.get(char) + v2.get(char)), dup), new Map());
};
const test = (v1,v2) => (console.log('{ '+Array.from(calcCommonCharFreq(v1, v2)).reduce((pairs, value) => (pairs.push('"'+value[0]+'": '+value[1]), pairs), []).join(", ")+' }'), test);
test("Leopard", "Lion") // { "L": 2, "o": 2 }
("Hello", "World") // { "l": 3, "o": 2 }
("Flower", "Power") // { "o": 2, "w": 2, "e": 2, "r": 2 }
("phone", "Memphis") // { "p": 2, "h": 2, "e": 2 }
("Bookkeeper", "Zookeeper") // { "o": 4, "k": 3, "e": 6, "p": 2, "r": 2 }
("Some thing", "Other thing"); // { "e": 2, " ": 2, "t": 3, "h": 3, "i": 2, "n": 2, "g": 2 }
答案 1 :(得分:1)
我将从一个名为if($cek_user->num_rows()>0){
$row = $cek_user->row();
$cek = $row ->hak_akses;
if($cek=='admin'){
$ambil = $this->db->query("SELECT table_name FROM information_schema.tables WHERE table_schema='public' and table_name != 'tablelogin'");
return $ambil->result();
}
else if($cek=='semi_admin'){
$ambil = $this->db->query("SELECT table_name FROM information_schema.tables WHERE table_schema='public' and table_name != 'tablelogin' and table_name != 'Film' and table_name != 'Hewan'");
return $ambil->result();
}
else if($cek == 'user'){
$ambil = $this->db->query("SELECT table_name FROM information_schema.tables WHERE table_schema='public' and table_name != 'tablelogin' and table_name != 'Gudang' and table_name != 'inventaris' and table_name != 'Pegawai'");
return $ambil->result();
}
}
else {
$hasil = null;
}
的简单函数开始,计算单个字符串中字符的出现次数。您可以在其他地方找到这个,但我提供了一个简单的版本。输出是一个按字符键入的对象,计数为值。
然后我们可以解决在两个字符串中找到匹配字符的问题,作为两个对象的合并,我们在一个名为countChars
的函数中实现。
combineObjectsByKey

你也可以简单地连接字符串,计算连接字符串中的字符,然后删除两个字符串中没有出现的字符:
function countChars(str) {
return str.split('').reduce((result, chr) => {
if (!(chr in result)) result[chr] = 0;
result[chr]++;
return result;
}, {});
}
function combineObjectsByKey(o1, o2, fn) {
const result = {};
Object.keys(o1).forEach(key => {
if (key in o2) result[key] = fn(o1[key], o2[key]);
});
return result;
}
function add(a, b) { return a + b; }
function matchingCounts(str1, str2) {
return combineObjectsByKey(countChars(str1), countChars(str2), add);
}
console.log(matchingCounts("Leopard", "Lion"));
答案 2 :(得分:0)
这是一个应该是FAST的选项(主要是因为它根本没有做任何花哨的事情)。这将解释字符大小写敏感,所有小写字母a-z字符,所有大写字母A-Z字符,数字0-9字符和空字符字符。
这里我只使用并行数组作为第一个和第二个字的字符的ASCII字符值。
xml = XML.toString(invoiceDetailObj);
以下是此代码的jsFiddle,可供使用和测试。
答案 3 :(得分:0)
虽然这个例子可能更优雅,但我认为这种方法更简单,更具可读性。
这是一个Pen来玩。
function getRepeated(x, y) {
let result = [];
x.split('').forEach(value => {
let array = testCharacterToString(value, y);
if (array.length > 0) {
result.push(array[0]);
}
});
y.split('').forEach(value => {
let array = testCharacterToString(value, x);
if (array.length > 0) {
result.push(array[0]);
}
});
result = result.reduce(function(prev, cur) {
prev[cur] = (prev[cur] || 0) + 1;
return prev;
}, {});
return JSON.stringify(result) // {"o":4,"k":3,"e":6,"p":2,"r":2}
}
function testCharacterToString(char, string) {
return string.split('').filter(value => {
return value === char;
});
}
var test = function(arg1,arg2){ return (console.log(getRepeated(arg1, arg2)),test) };
test("Leopard", "Lion") // { "L": 2, "o": 2 }
("Hello", "World") // { "l": 3, "o": 2 }
("Flower", "Power") // { "o": 2, "w": 2, "e": 2, "r": 2 }
("phone", "Memphis") // { "p": 2, "h": 2, "e": 2 }
("Bookkeeper", "Zookeeper") // { "o": 4, "k": 3, "e": 6, "p": 2, "r": 2 }
("Some thing", "Other thing"); // { "e": 2, " ": 2, "t": 3, "h": 3, "i": 2, "n": 2, "g": 2 }
答案 4 :(得分:0)
这是一个非常好的问题。如果我做对了,你可以很容易地在O(2n)中做如下;
function relationIndex(s){
var a = s.split(/\s+/),
hash = a[0].length < a[1].length ? Array.prototype.reduce.call(a[1], (p,c) => (p[c] && (p[c] = Math.abs(p[c])+1),p), Array.prototype.reduce.call(a[0], (p,c) => (p[c] = --p[c] || -1,p),{}))
: Array.prototype.reduce.call(a[0], (p,c) => (p[c] && (p[c] = Math.abs(p[c])+1),p), Array.prototype.reduce.call(a[1], (p,c) => (p[c] = --p[c] || -1,p),{}));
for (var k in hash) hash[k] <= 0 && delete hash[k];
return hash;
}
var str = "Lion Leopard";
console.log(relationIndex(str));
str = "Brontosaurus Butterfly";
console.log(relationIndex(str));
str = "London Paris";
console.log(relationIndex(str));
str = "phone Memphis";
console.log(relationIndex(str));
&#13;
答案 5 :(得分:-1)
这是一个更易读的版本的缩略图...
function count(v1, v2) {
let map = {};
Array.prototype.forEach.call(v1, char => map[char] = map[char]++ || 1);
Array.prototype.forEach.call(v2, char => {
if(map[char]) map[char] += 1;
});
for(let char in map) {
if(map[char] < 2) {
delete map[char];
}
}
console.log(map)
}
count('Lion', 'Leopard');