Splitting string in 2 parts by removing substring in golang - string

I'm trying to parse strings that look something like this:
abc***********xyz
into a slice (or 2 variables) of "abc" and "xyz", removing all the asterisks.
The number of * can be variable and so can the letters on each side, so it's not necessarily a fixed length. I'm wondering if go has a nice way of doing this with the strings package?

Use strings.FieldsFunc where * is a field separator.
s := "abc***********xyz"
z := strings.FieldsFunc(s, func(r rune) bool { return r == '*' })
fmt.Println(len(z), z) // prints 2 [abc xyz]
Live Example.

Split on any number of asterisks:
words := regexp.MustCompile(`\*+`).Split(str, -1)
See live demo.

For best performance, write a for loop:
func SplitAsteriks(s string) []string {
var (
in bool // true if inside a token
tokens []string // collect function result here
i int
)
for j, r := range s {
if r == '*' {
if in {
// transition from token to separator
tokens = append(tokens, s[i:j])
in = false
}
} else {
if !in {
// transition from one or more separators to token
i = j
in = true
}
}
}
if in {
tokens = append(tokens, s[i:])
}
return tokens
}
Playground.

if performance is an issue, you can use this func:
func SplitAsteriks(s string) (result []string) {
if len(s) == 0 {
return
}
i1, i2 := 0, 0
for i := 0; i < len(s); i++ {
if s[i] == '*' && i1 == 0 {
i1 = i
}
if s[len(s)-i-1] == '*' && i2 == 0 {
i2 = len(s) - i
}
if i1 > 0 && i2 > 0 {
result = append(result, s[:i1], s[i2:])
return
}
}
result = append(result, s)
return
}
playground

Use this code given that the string is specified to have two parts:
s := "abc***********xyz"
p := s[:strings.IndexByte(s, '*')]
q := s[strings.LastIndexByte(s, '*')+1:]
fmt.Println(p, q) // prints abc xyz

Related

Optimizing Jaro-Winkler algorithm in Golang

I need to run Jaro Wrinkler 1500000 times for finding similarity between given []byte to exiting []byte. I took the code from https://rosettacode.org/wiki/Jaro-Winkler_distance#Go and modified it to work directly on []byte instead of string.
func JaroWrinkler(a, b []byte) float64 {
lenPrefix := len(commonPrefix(a, b))
if lenPrefix > 4 {
lenPrefix = 4
}
// Return similarity.
similarity := JaroSim(a, b)
return similarity + (0.1 * float64(lenPrefix) * (1.0 - similarity))
}
func JaroSim(str1, str2 []byte) float64 {
if len(str1) == 0 && len(str2) == 0 {
return 1
}
if len(str1) == 0 || len(str2) == 0 {
return 0
}
match_distance := len(str1)
if len(str2) > match_distance {
match_distance = len(str2)
}
match_distance = match_distance/2 - 1
str1_matches := make([]bool, len(str1))
str2_matches := make([]bool, len(str2))
matches := 0.
transpositions := 0.
for i := range str1 {
start := i - match_distance
if start < 0 {
start = 0
}
end := i + match_distance + 1
if end > len(str2) {
end = len(str2)
}
for k := start; k < end; k++ {
if str2_matches[k] {
continue
}
if str1[i] != str2[k] {
continue
}
str1_matches[i] = true
str2_matches[k] = true
matches++
break
}
}
if matches == 0 {
return 0
}
k := 0
for i := range str1 {
if !str1_matches[i] {
continue
}
for !str2_matches[k] {
k++
}
if str1[i] != str2[k] {
transpositions++
}
k++
}
transpositions /= 2
return (matches/float64(len(str1)) +
matches/float64(len(str2)) +
(matches-transpositions)/matches) / 3
}
func commonPrefix(first, second []byte) []byte {
if len(first) > len(second) {
first, second = second, first
}
var commonLen int
sRunes := []byte(second)
for i, r := range first {
if r != sRunes[i] {
break
}
commonLen++
}
return sRunes[0:commonLen]
}
I benchmarked it with the https://github.com/adrg/strutil package, and it outperformed.
It is very slow for my use case. Can it be optimised more?

How to split string two between characters

I want to split a string up between two characters( {{ and }} ).
I have an string like {{number1}} + {{number2}} > {{number3}}
and I'm looking for something that returns:
[number1, number2, number3]
You can try it with Regex:
s := "{{number1}} + {{number2}} > {{number3}}"
// Find all substrings in form {<var name>}
re := regexp.MustCompile("{[a-z]*[0-9]*[a-z]*}")
nums := re.FindAllString(s, -1)
// Remove '{' and '}' from all substrings
for i, _ := range nums {
nums[i] = strings.TrimPrefix(nums[i], "{")
nums[i] = strings.TrimSuffix(nums[i], "}")
}
fmt.Println(nums) // output: [number1 number2 number3]
You can experiment with regex here: https://regex101.com/r/kkPWAS/1
Use the regex [A-Za-z]+[0-9] and filter the alpha numeric parts of the string as string array.
package main
import (
"fmt"
"regexp"
)
func main() {
s := `{{number1}} + {{number2}} > {{number3}}`
re := regexp.MustCompile("[A-Za-z]+[0-9]")
p := re.FindAllString(s, -1)
fmt.Println(p) //[number1 number2 number3]
}
the hard way using the template parser ^^
package main
import (
"fmt"
"strings"
"text/template/parse"
)
func main() {
input := "{{number1}} + {{number2}} > {{number3}}"
out := parseit(input)
fmt.Printf("%#v\n", out)
}
func parseit(input string) (out []string) {
input = strings.Replace(input, "{{", "{{.", -1) // Force func calls to become variables.
tree, err := parse.Parse("", input, "{{", "}}")
if err != nil {
panic(err)
}
visit(tree[""].Root, func(n parse.Node) bool {
x, ok := n.(*parse.FieldNode)
if ok {
out = append(out, strings.Join(x.Ident, "."))
}
return true
})
return
}
func visit(n parse.Node, fn func(parse.Node) bool) bool {
if n == nil {
return true
}
if !fn(n) {
return false
}
if l, ok := n.(*parse.ListNode); ok {
for _, nn := range l.Nodes {
if !visit(nn, fn) {
continue
}
}
}
if l, ok := n.(*parse.RangeNode); ok {
if !visit(l.BranchNode.Pipe, fn) {
return false
}
if l.BranchNode.List != nil {
if !visit(l.BranchNode.List, fn) {
return false
}
}
if l.BranchNode.ElseList != nil {
if !visit(l.BranchNode.ElseList, fn) {
return false
}
}
}
if l, ok := n.(*parse.ActionNode); ok {
for _, c := range l.Pipe.Decl {
if !visit(c, fn) {
continue
}
}
for _, c := range l.Pipe.Cmds {
if !visit(c, fn) {
continue
}
}
}
if l, ok := n.(*parse.CommandNode); ok {
for _, a := range l.Args {
if !visit(a, fn) {
continue
}
}
}
if l, ok := n.(*parse.PipeNode); ok {
for _, a := range l.Decl {
if !visit(a, fn) {
continue
}
}
for _, a := range l.Cmds {
if !visit(a, fn) {
continue
}
}
}
return true
}
If it happens you really were manipulating template string, but fails to do so due to function calls and that you do not want to execute this input = strings.Replace(input, "{{", "{{.", -1) // Force func calls to become variables.
You can always force load a template using functions similar to
var reMissingIdent = regexp.MustCompile(`template: :[0-9]+: function "([^"]+)" not defined`)
func ParseTextTemplateAnyway(s string) (*texttemplate.Template, texttemplate.FuncMap, error) {
fn := texttemplate.FuncMap{}
for {
t, err := texttemplate.New("").Funcs(fn).Parse(s)
if err == nil {
return t, fn, err
}
s := err.Error()
res := reMissingIdent.FindAllStringSubmatch(s, -1)
if len(res) > 0 {
fn[res[0][1]] = func(s ...interface{}) string { return "" }
} else {
return t, fn, err
}
}
// return nil, nil
}
You don't need to use libraries. You can create your own function.
package main
const r1 = '{'
const r2 = '}'
func GetStrings(in string) (out []string) {
var tren string
wr := false
f := true
for _, c := range in {
if wr && c != r2 {
tren = tren + string(c)
}
if c == r1 {
f = !f
wr = f
}
if c == r2 {
wr = false
if f {
out = append(out, tren)
tren = ""
}
f = !f
}
}
return
}

GoLang Get String at Line N in Byte Slice

In a personal project I am implementing a function that returns a random line from a long file. For it to work I have to create a function that returns a string at line N, a second function that creates a random number between 0 and lines in file. While I was implementing those I figured it may be more efficient to store the data in byte slices by default, rather than storing them in separate files, which have to be read at run time.
Question: How would I go about implementing a function that returns a string at a random line of the []byte representation of my file.
My function for getting a string from a file:
func atLine(n int) (s string) {
f, err := os.Open("./path/to/file")
if err != nil {
panic("Could not read file.")
}
defer f.Close()
r := bufio.NewReader(f)
for i := 1; ; i++ {
line, _, err := r.ReadLine()
if err != nil {
break
}
if i == n {
s = string(line[:])
break
}
}
return s
}
Additional info:
Lines are not longer than 50 characters at most
Lines have no special characters (although a solution handling those is welcome)
Number of lines in the files is known and so the same can be applied for []byte
Dealing with just the question part (and not the sanity of this) - you have a []byte and want to get a specific string line from it - the bytes.Reader has no ReadLine method which you will have already noticed.
You can pass a bytes reader to bufio.NewReader, and gain the ReadLine functionality you are trying to access.
bytesReader := bytes.NewReader([]byte("test1\ntest2\ntest3\n"))
bufReader := bufio.NewReader(bytesReader)
value1, _, _ := bufReader.ReadLine()
value2, _, _ := bufReader.ReadLine()
value3, _, _ := bufReader.ReadLine()
fmt.Println(string(value1))
fmt.Println(string(value2))
fmt.Println(string(value3))
Obviously it is not sensible to ignore the errors, but for the purpose of brevity I do it here.
https://play.golang.org/p/fRQUfmZQke
Results:
test1
test2
test3
From here, it is straight forward to fit back into your existing code.
Here is an example of fast (in the order of nanoseconds) random access to lines of text as byte data. The data is buffered and indexed in memory.
lines.go:
package main
import (
"bytes"
"fmt"
"io/ioutil"
"os"
)
type Lines struct {
data []byte
index []int // line start, end pairs for data[start:end]
}
func NewLines(data []byte, nLines int) *Lines {
bom := []byte{0xEF, 0xBB, 0xBF}
if bytes.HasPrefix(data, bom) {
data = data[len(bom):]
}
lines := Lines{data: data, index: make([]int, 0, 2*nLines)}
for i := 0; ; {
j := bytes.IndexByte(lines.data[i:], '\n')
if j < 0 {
if len(lines.data[i:]) > 0 {
lines.index = append(lines.index, i)
lines.index = append(lines.index, len(lines.data))
}
break
}
lines.index = append(lines.index, i)
j += i
i = j + 1
if j > 0 && lines.data[j-1] == '\r' {
j--
}
lines.index = append(lines.index, j)
}
if len(lines.index) != cap(lines.index) {
lines.index = append([]int(nil), lines.index...)
}
return &lines
}
func (l *Lines) N() int {
return len(l.index) / 2
}
func (l *Lines) At(n int) (string, error) {
if 1 > n || n > l.N() {
err := fmt.Errorf(
"data has %d lines: at %d out of range",
l.N(), n,
)
return "", err
}
m := 2 * (n - 1)
return string(l.data[l.index[m]:l.index[m+1]]), nil
}
var (
// The Complete Works of William Shakespeare
// http://www.gutenberg.org/cache/epub/100/pg100.txt
fName = `/home/peter/shakespeare.pg100.txt`
nLines = 124787
)
func main() {
data, err := ioutil.ReadFile(fName)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
lines := NewLines(data, nLines)
for _, at := range []int{1 - 1, 1, 2, 12, 42, 124754, lines.N(), lines.N() + 1} {
line, err := lines.At(at)
if err != nil {
fmt.Fprintf(os.Stderr, "%d\t%v\n", at, err)
continue
}
fmt.Printf("%d\t%q\n", at, line)
}
}
Output:
0 data has 124787 lines: at 0 out of range
1 "The Project Gutenberg EBook of The Complete Works of William Shakespeare, by"
2 "William Shakespeare"
12 "Title: The Complete Works of William Shakespeare"
42 "SHAKESPEARE IS COPYRIGHT 1990-1993 BY WORLD LIBRARY, INC., AND IS"
124754 "http://www.gutenberg.org"
124787 "*** END: FULL LICENSE ***"
124788 data has 124787 lines: at 124788 out of range
lines_test.go:
package main
import (
"io/ioutil"
"math/rand"
"testing"
)
func benchData(b *testing.B) []byte {
data, err := ioutil.ReadFile(fName)
if err != nil {
b.Fatal(err)
}
return data
}
func BenchmarkNewLines(b *testing.B) {
data := benchData(b)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
lines := NewLines(data, nLines)
_ = lines
}
}
func BenchmarkLineAt(b *testing.B) {
data := benchData(b)
lines := NewLines(data, nLines)
ats := make([]int, 4*1024)
ats[0], ats[1] = 1, lines.N()
rand.Seed(42)
for i := range ats[2:] {
ats[2+i] = 1 + rand.Intn(lines.N())
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
at := ats[i%len(ats)]
line, err := lines.At(at)
if err != nil {
b.Error(err)
}
_ = line
}
}
Output
$ go test -bench=. lines.go lines_test.go
BenchmarkNewLines-8 1000 1898347 ns/op 1998898 B/op 2 allocs/op
BenchmarkLineAt-8 50000000 45.1 ns/op 49 B/op 0 allocs/op

Add slash to string every n characters [duplicate]

I have a string which contains binary digits. How to separate it in to pairs of digits?
Suppose the string is:
let x = "11231245"
I want to add a separator such as ":" (i.e., a colon) after each 2 characters.
I would like the output to be:
"11:23:12:45"
How could I do this in Swift ?
Swift 5.2 • Xcode 11.4 or later
extension Collection {
func unfoldSubSequences(limitedTo maxLength: Int) -> UnfoldSequence<SubSequence,Index> {
sequence(state: startIndex) { start in
guard start < endIndex else { return nil }
let end = index(start, offsetBy: maxLength, limitedBy: endIndex) ?? endIndex
defer { start = end }
return self[start..<end]
}
}
func every(n: Int) -> UnfoldSequence<Element,Index> {
sequence(state: startIndex) { index in
guard index < endIndex else { return nil }
defer { let _ = formIndex(&index, offsetBy: n, limitedBy: endIndex) }
return self[index]
}
}
var pairs: [SubSequence] { .init(unfoldSubSequences(limitedTo: 2)) }
}
extension StringProtocol where Self: RangeReplaceableCollection {
mutating func insert<S: StringProtocol>(separator: S, every n: Int) {
for index in indices.every(n: n).dropFirst().reversed() {
insert(contentsOf: separator, at: index)
}
}
func inserting<S: StringProtocol>(separator: S, every n: Int) -> Self {
.init(unfoldSubSequences(limitedTo: n).joined(separator: separator))
}
}
Testing
let str = "112312451"
let final0 = str.unfoldSubSequences(limitedTo: 2).joined(separator: ":")
print(final0) // "11:23:12:45:1"
let final1 = str.pairs.joined(separator: ":")
print(final1) // "11:23:12:45:1"
let final2 = str.inserting(separator: ":", every: 2)
print(final2) // "11:23:12:45:1\n"
var str2 = "112312451"
str2.insert(separator: ":", every: 2)
print(str2) // "11:23:12:45:1\n"
var str3 = "112312451"
str3.insert(separator: ":", every: 3)
print(str3) // "112:312:451\n"
var str4 = "112312451"
str4.insert(separator: ":", every: 4)
print(str4) // "1123:1245:1\n"
I'll go for this compact solution (in Swift 4) :
let s = "11231245"
let r = String(s.enumerated().map { $0 > 0 && $0 % 2 == 0 ? [":", $1] : [$1]}.joined())
You can make an extension and parameterize the stride and the separator so that you can use it for every value you want (In my case, I use it to dump 32-bit space-operated hexadecimal data):
extension String {
func separate(every stride: Int = 4, with separator: Character = " ") -> String {
return String(enumerated().map { $0 > 0 && $0 % stride == 0 ? [separator, $1] : [$1]}.joined())
}
}
In your case this gives the following results:
let x = "11231245"
print (x.separate(every:2, with: ":")
$ 11:23:12:45
Swift 5.3
/// Adds a separator at every N characters
/// - Parameters:
/// - separator: the String value to be inserted, to separate the groups. Default is " " - one space.
/// - stride: the number of characters in the group, before a separator is inserted. Default is 4.
/// - Returns: Returns a String which includes a `separator` String at every `stride` number of characters.
func separated(by separator: String = " ", stride: Int = 4) -> String {
return enumerated().map { $0.isMultiple(of: stride) && ($0 != 0) ? "\(separator)\($1)" : String($1) }.joined()
}
Short and simple, add a let or two if you want
extension String {
func separate(every: Int, with separator: String) -> String {
return String(stride(from: 0, to: Array(self).count, by: every).map {
Array(Array(self)[$0..<min($0 + every, Array(self).count)])
}.joined(separator: separator))
}
}
let a = "separatemepleaseandthankyou".separate(every: 4, with: " ")
a is
sepa rate mepl ease andt hank you
Its my code in swift 4
let x = "11231245"
var newText = String()
for (index, character) in x.enumerated() {
if index != 0 && index % 2 == 0 {
newText.append(":")
}
newText.append(String(character))
}
print(newText)
Outputs 11:23:12:45
My attempt at that code would be:
func insert(seperator: String, afterEveryXChars: Int, intoString: String) -> String {
var output = ""
intoString.characters.enumerate().forEach { index, c in
if index % afterEveryXChars == 0 && index > 0 {
output += seperator
}
output.append(c)
}
return output
}
insert(":", afterEveryXChars: 2, intoString: "11231245")
Which outputs
11:23:12:45
let y = String(
x.characters.enumerate().map() {
$0.index % 2 == 0 ? [$0.element] : [$0.element, ":"]
}.flatten()
)
A simple One line of code for inserting separater ( Swift 4.2 ):-
let testString = "123456789"
let ansTest = testString.enumerated().compactMap({ ($0 > 0) && ($0 % 2 == 0) ? ":\($1)" : "\($1)" }).joined() ?? ""
print(ansTest) // 12:34:56:78:9
Swift 4.2.1 - Xcode 10.1
extension String {
func insertSeparator(_ separatorString: String, atEvery n: Int) -> String {
guard 0 < n else { return self }
return self.enumerated().map({String($0.element) + (($0.offset != self.count - 1 && $0.offset % n == n - 1) ? "\(separatorString)" : "")}).joined()
}
mutating func insertedSeparator(_ separatorString: String, atEvery n: Int) {
self = insertSeparator(separatorString, atEvery: n)
}
}
Usage
let testString = "11231245"
let test1 = testString.insertSeparator(":", atEvery: 2)
print(test1) // 11:23:12:45
var test2 = testString
test2.insertedSeparator(",", atEvery: 3)
print(test2) // 112,312,45
I'm little late here, but i like to use regex like in this:
extension String {
func separating(every: Int, separator: String) -> String {
let regex = #"(.{\#(every)})(?=.)"#
return self.replacingOccurrences(of: regex, with: "$1\(separator)", options: [.regularExpression])
}
}
"111222333".separating(every: 3, separator: " ")
the output:
"111 222 333"
extension String{
func separate(every: Int) -> [String] {
return stride(from: 0, to: count, by: every).map {
let ix0 = index(startIndex, offsetBy: $0);
let ix1 = index(after:ix0);
if ix1 < endIndex {
return String(self[ix0...ix1]);
}else{
return String(self[ix0..<endIndex]);
}
}
}
/// or O(1) implementation (without count)
func separate(every: Int) -> [String] {
var parts:[String] = [];
var ix1 = startIndex;
while ix1 < endIndex {
let ix0 = ix1;
var n = 0;
while ix1 < endIndex && n < every {
ix1 = index(after: ix1);
n += 1;
}
parts.append(String(self[ix0..<ix1]));
}
return parts;
}
"asdf234sdf".separate(every: 2).joined(separator: ":");
A simple String extension that doesn't require the original string to be a multiple of the step size (increment):
extension String {
func inserted(_ newElement: Character,atEach increment:Int)->String {
var newStr = self
for indx in stride(from: increment, to: newStr.count, by: increment).reversed() {
let index = String.Index(encodedOffset: indx)
newStr.insert(newElement, at: index)
}
return newStr
}
}

Check if a permutation of a string can become a palindrome

Write a method to test if a string meets the preconditions to become a palindrome.
Eg:
Input | Output
mmo | True
yakak | True
travel | False
I'm thinking of this approach:
Make a suffix tree for all permutation of T such that T$Reverse(T)#
Check for all permutation for same node
Am I missing anything?
All you need to do is check that there's at most one character with an odd number of occurrences. Here's a Java example:
private static boolean canMakePalindrom(String s) {
Map<Character, Integer> countChars = new HashMap<>();
// Count the occurrences of each character
for (char c : s.toCharArray()) {
Integer count = countChars.get(c);
if (count == null) {
count = Integer.valueOf(1);
} else {
count = count + 1;
}
countChars.put(c, count);
}
boolean hasOdd = false;
for (int count : countChars.values()) {
if (count % 2 == 1) {
if (hasOdd) {
// Found two chars with odd counts - return false;
return false;
} else {
// Found the first char with odd count
hasOdd = true;
}
}
}
// Haven't found more than one char with an odd count
return true;
}
EDIT4 (yes - these are ordered to make sense, but numbered by chronological order):
The above implementation has a built in inefficiency. I don't think the first iteration over the string can be avoided, but there's no real reason to keep a count of all the occurrences - it's enough to just keep track of those with the an odd count. For this usecase, it's enough to keep track of each character we encounter (e.g., with a Set), and remove it when we encounter it again. In the worst case, where all the characters in the string are different, the performance is comparable, but in the common case, where there are several occurrences of each character, this implementation improves both time and memory complexity of the second loop (which is now reduced to a single condition) dramatically:
private static boolean canMakePalindrom(String s) {
Set<Character> oddChars = new HashSet<>();
// Go over the characters
for (char c : s.toCharArray()) {
// Record the encountered character:
if (!oddChars.add(c)) {
// If the char was already encountered, remove it -
// this is an even time we encounter it
oddChars.remove(c);
}
}
// Check the number of characters with odd counts:
return oddChars.size() <= 1;
}
EDIT3 (yes - these are ordered to make sense, but numbered by chronological order):
Java 8 provides a fluent streaming API which could be used to create an implementation similar to the Python one-liners below:
private static boolean canMakePalindrom(String s) {
return s.chars()
.boxed()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()))
.values()
.stream()
.filter(p -> p % 2 == 1)
.count() <= 1;
}
EDIT:
Python built-in functions and comprehension capabilities make this too attractive not to publish this one liner solution. It's probably less efficient than the aforementioned Java one, but is quite elegant:
from collections import Counter
def canMakePalindrom(s):
return len([v for v in Counter(s).values() if v % 2 == 1]) <= 1
EDIT2:
Or, an even cleaner approach as proposed by #DSM in the comments:
from collections import Counter
def canMakePalindrom(s):
return sum(v % 2 == 1 for v in Counter(s).values()) <= 1
Instead of counting how many times each letter occurs, another approach keeps track of whether a letter has occurred an odd or even number of times. If a letter has occurred an even number of times, you don’t need to worry about it, and only need to keep track of the odd occurrences in a set. In Java:
public static boolean canMakePalindrome(String s) {
Set<Character> oddLetters = new HashSet<>();
for ( char c : s.toCharArray() ) {
if ( ! oddLetters.remove(c) ) {
oddLetters.add(c);
}
}
return oddLetters.size() <= 1;
}
Really all you're looking for is if all (or all but one) of the letters are paired off. As long as they are, then they will be able to be turned into a palindrome.
So it would be something like...
bool canBeTurnedIntoAPalindrome(string drome)
{
// If we've found a letter that has no match, the center letter.
bool centerUsed = false;
char center;
char c;
int count = 0;
// TODO: Remove whitespace from the string.
// Check each letter to see if there's an even number of it.
for(int i = 0; i<drome.length(); i++)
{
c = drome[i];
count = 0;
for(int j = 0; j < drome.length(); j++)
if (drome[j] == c)
count++;
// If there was an odd number of those entries
// and the center is already used, then a palindrome
// is impossible, so return false.
if (count % 2 == 1)
{
if (centerUsed == true && center != c)
return false;
else
{
centerused = true;
center = c; // This is so when we encounter it again it
// doesn't count it as another separate center.
}
}
}
// If we made it all the way through that loop without returning false, then
return true;
}
This isn't the most efficient (it's counting letters as many times as it comes across them, even if they've been counted already) but it does work.
If I'm understanding your question correctly, this is how I understand it:
If the input string can be rearranged into a palindrome, output "True", otherwise output "False".
Then you can use these simple rules:
If the length is even, every unique character in the input has to occur a multiple of 2 times.
If the length is odd, every unique character except one has to occur a multiple of 2 times. Only 1 character is allowed to not occur a multiple of 2 times.
So for the 3 given examples:
"mmo", odd length, m occurs twice (multiple of 2), o occurs once (not a multiple of 2), so True.
"yakak", odd length, a occurs twice (multiple of 2), k occurs twice (multiple of 2), y occurs once (not a multiple of 2) , so True.
"travel", more than one character does not occur a multiple of 2, so False.
Additional examples:
"mmorpg", only m occurs a multiple of 2, the rest only once, so False.
"mmom", no characters occur a multiple of 2, more than one character occurs "not a multiple of 2 times", so False.
At this point you should realise that if only 1 character is allowed to occur a non-multiple-of-2 times, then you can disregard the length. A string with an even length will have either 2 or more characters occuring a non-multiple-of-2 times, or none at all.
So the final rule should be this:
If at most 1 unique character occurs a non-multiple-of-2 times in the input, the output is True otherwise the output is False.
def can_permutation_palindrome(s):
counter = {}
for c in s:
counter[c] = counter.get(c, 0) + 1
odd_count = 0
for count in counter.values():
odd_count += count % 2
return odd_count in [0, 1]
def check(string):
bv = 0
for s in string:
bv ^= 1 << ord(s)
return bv == 0 or bv & (bv - 1) == 0
I reached the solution below today (python). I think it's readable, and performance-wise it's really good.
sum(map(lambda x: word.count(x) % 2, set(word))) <= 1
We're basically counting the number of occurrences of each character in the string "word", getting the remainder of the division by 2, summing them all and checking if you have at most 1 of them.
The idea is that you need to have all characters paired, except potentially for one (the middle one).
My idea is, if the number of letters with odd count is one and rest all have even count, a palindrome is possible..Here's my program in Python
string = raw_input()
found = False
char_set = set(string) # Lets find unique letters
d_dict = {}
for c in char_set:
d_dict[c] = string.count(c) # Keep count of each letter
odd_l = [e for e in d_dict.values() if e%2 == 1] # Check how many has odd number of occurrence
if len(odd_l) >1:
pass
else:
found = True
if not found:
print("NO")
else:
print("YES")
Any string can be palindrome only if at most one character occur odd no. of times and all other characters must occur even number of times. The following program can be used to check whether a palindrome can be string or not.
void checkPalindrome(string s)
{
vector<int> vec(256,0); //Vector for all ASCII characters present.
for(int i=0;i<s.length();++i)
{
vec[s[i]-'a']++;
}
int odd_count=0,flag=0;
for(int i=0;i<vec.size();++i)
{
if(vec[i]%2!=0)
odd_count++;
if(odd_count>1)
{
flag=1;
cout<<"Can't be palindrome"<<endl;
break;
}
}
if(flag==0)
cout<<"Yes can be palindrome"<<endl;
}
With O(n) complexity .
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PallindromePemutation
{
class charcount
{
public char character { get; set; }
public int occurences { get; set; }
}
class Program
{
static void Main(string[] args)
{
List<charcount> list = new List<charcount>();
charcount ch;
int count = 0;
char[] arr = "travel".ToCharArray();
for (int i = 0; i < arr.Length; i++)
{
charcount res = list.Find(x => x.character == arr.ElementAt(i));
if (res == null)
{
ch = new charcount();
ch.character = arr.ElementAt(i);
ch.occurences = 1;
list.Add(ch);
}
else
{
charcount temp= list.Find(x => x.character == arr.ElementAt(i));
temp.occurences++;
}
}
foreach (var item in list)
{
if (!(item.occurences % 2 == 0))
{
count++;
}
}
if (count > 1)
{
Console.WriteLine("false");
}
else
{
Console.WriteLine("true");
}
Console.ReadKey();
}
}
}
If we don't care case sensitivity of characters and spaces within a string, then a sample solution in C# by using Dictionary can be like :
private static bool IsPalindromePermutation(string inputStr)
{
// First, check whether input string is null or whitespace.
// If yes, then return false.
if (string.IsNullOrWhiteSpace(inputStr))
return false;
var inputDict = new Dictionary<char, int>();
// Big/small letter is not important
var lowerInputStr = inputStr.ToLower();
// Fill input dictionary
// If hit a space, then skip it
for (var i = 0; i < lowerInputStr.Length; i++)
{
if (lowerInputStr[i] != ' ')
{
if (inputDict.ContainsKey(lowerInputStr[i]))
inputDict[lowerInputStr[i]] += 1;
else
inputDict.Add(lowerInputStr[i], 1);
}
}
var countOdds = 0;
foreach(var elem in inputDict)
{
if(elem.Value % 2 != 0)
countOdds++;
}
return countOdds <= 1;
}
We can acheive this via collections also
String name = "raa";
List<Character> temp = new ArrayList<>(name.chars()
.mapToObj(e -> (char) e).collect(Collectors.toList()));
for (int i = 0; i < temp.size(); i++) {
for (int j = i + 1; j < temp.size(); j++) {
if (temp.get(i).equals(temp.get(j))) {
temp.remove(j);
temp.remove(i);
i--;
}
}
}
if (temp.size() <= 1) {
System.out.println("Pallindrome");
} else {
System.out.println(temp.size());
System.out.println("Not Pallindrome");
}
}
This is my solution
public static void main(String[] args) {
List<Character> characters = new ArrayList<>();
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
for (int i = 0; i < input.length(); i++){
char val = input.charAt(i);
if (characters.contains(val)){
characters.remove(characters.indexOf(val));
} else{
characters.add(val);
}
}
if (characters.size() == 1 || characters.size() == 0){
System.out.print("Yes");
} else{
System.out.print("No");
}
}
That 's my solution. The string could contain several words with spaces, such as
Input: Tact Coa
Output true
Input: Tact Coa vvu
Output: false
public static boolean checkForPalindrome(String str) {
String strTrimmed = str.replaceAll(" ","");
System.out.println(strTrimmed);
char[] str1 = strTrimmed.toCharArray();
for (int i = 0; i < str1.length; i++) {
str1[i] = Character.toLowerCase(str1[i]);
}
Arrays.sort(str1);
String result = new String(str1);
System.out.println(result);
int count = 0;
for (int j = 0; j < str1.length; j += 2) {
if (j != str1.length-1) {
if (str1[j] != str1[j+1]) {
count++;
j++;
}
} else {
count++;
}
}
if (count > 1) return false;
else return true;
}
Question: Can a String become a palindrome?
Method1: count of characters
IN Java :
public class TEST11 {
public static void main(String[] args) {
String a = "Protijayi";
int[] count = new int[256];
Arrays.fill(count, 0);
for (int i = 0; i < a.length(); i++) {
char ch = a.charAt(i);
count[ch]++;
} // for
// counting of odd letters
int odd = 0;
for (int i = 0; i < count.length; i++) {
if ((count[i] & 1) == 1) {
odd++;
}
} // for
if (odd > 1) {
System.out.println("no");
} else {
System.out.println("yes");
}
}
}
IN Python:
def fix (a):
count = [0] * 256
for i in a: count[ord(i)] += 1
# counting of odd characters
odd = 0
for i in range(256):
if((count[i] & 1) == 1): odd += 1
if(odd > 1):print("no")
else:print("yes")
a = "Protijayi"
fix(a)
Method 2 : Use of HashSet
In Java:
public class TEST11 {
public static void main(String[] args) {
String a = "Protijayi";
Set<Character> set = new HashSet<>();
for (char ch : a.toCharArray()) {
if (set.contains(ch)) {
set.remove(ch);
}
set.add(ch);
} // for
if (set.size() <= 1) {
System.out.println("yes can be a palindrome");
} else {
System.out.println("no");
}
}
}
Swift example for this question.
var str = "mmoosl"
extension String {
func count(of needle: Character) -> Int {
return reduce(0) {
$1 == needle ? $0 + 1 : $0
}
}
}
func canBeTurnedIntoAPalinpolyString(_ polyString: String) -> Bool {
var centerUsed = false
var center = Character("a")
for i in polyString {
let count = polyString.count(of: i)
if count == 1 && !centerUsed {
center = i
centerUsed = true
} else {
if count % 2 != 0 {
return false
}
}
}
return true
}
print(canBeTurnedIntoAPalinpolyString(str))
Java
private static boolean isStringPalindromePermutation(String input) {
if(input == null) return false;
if(input.isEmpty()) return false;
int checker = 0;
for (int i = 0; i < input.length(); i++) {
int character = input.charAt(i) - 'a';
int oneShiftedByNumberInCharacter = 1 << character;
int summaryAnd = checker & oneShiftedByNumberInCharacter;
if ( summaryAnd > 0 ) {
int revertToShiftedByChar = ~oneShiftedByNumberInCharacter;
checker = checker & revertToShiftedByChar;
} else {
checker |= oneShiftedByNumberInCharacter;
}
}
if ( input.length() % 2 == 0 ) {
if ( checker == 0) {
return true;
}
else return false;
} else {
int checkerMinusOne = checker-1;
if((checkerMinusOne & checker) == 0){
return true;
}else{
return false;
}
}
}
Why use a suffix tree or any other data structure?
The basic requirement of a palindromic string is the frequency of all characters must be even or only one character can have odd frequency.
Example :-
Input : aabbaa
Output : frequency of a is 4 and b is 2 (both even)
Input : xxzyzxx
Output : frequency of x is 4, z is 2 and y=1 (only 1 odd)
Sample code for better understanding :
bool ispalin(string str) //function to check
{
int freq[26] = {0}; //to store frequency of character here i am
// considering only lower case letters
for (int i = 0; str.length(); i++)
freq[str[i]]++;
int odd = 0;
for (int i = 0; i < 26; i++) //Count odd occurring characters
{
if (freq[i] & 1) //checking if odd
odd++;
if (odd > 1) //if number of odd freq is greater than 1
return false;
}
return true; //else return true
}
python code to check whether a palindrome can be formed from given string or not:
test_str = input('enter any string = ')
count = 0
for item in set(test_str):
if test_str.count(item)%2 != 0:
count+=1
if (count>1):
print(" palindrome cannot be formed")
else:
print(" palindrome can be formed")
Please try this code if any issue please comments
More efficient implementation - Java
boolean palindromeRearranging(String inputString) {
Map<Character, Integer> charsCount = new HashMap<Character, Integer>();
for(char c : inputString.toCharArray()){
charsCount.compute(c, (key, val) -> val == null ? 1 : val + 1);
}
List<Integer> result = new ArrayList<>();
charsCount.forEach((k, v) -> {
if(v % 2 != 0){
result.add(v);
}
});
return (result.size() == 0 || result.size() == 1);
}
Here is my code :
boolean palindromeRearranging(String inputString) {
HashMap<Character,Integer> stCount=new HashMap<>();
for(int i=0;i<inputString.length();i++){
stCount.put(inputString.charAt(i),0);
}
for(int i=0;i<inputString.length();i++){
int c= stCount.get(inputString.charAt(i));
stCount.put(inputString.charAt(i),++c);
}
int c=0;
for (Map.Entry<Character,Integer> entry : stCount.entrySet()){
if(entry.getValue()%2!=0){
c++;
if(c>1){
return false;
}
}
}
return true;
}
JS solution:
function solution(inputString) {
const arr = inputString.split('');
let hasCoupleList = arr.map( (el) => arr.filter( (el1) => el1 == el).length % 2 == 0).filter( (el) => el == false).length;
return (arr.length % 2 == 0)
? hasCoupleList == 0
: hasCoupleList == 1;
}
With JAVA
import java.util.*;
import java.lang.*;
//Classs
class Permutation {
/*
* We need to have an even number of almost all characters,
* so that half can be on one side and half can be on the other side.
* At most one character (the middle character) can have an odd count.
*/
public static boolean hasPalindrome(String str) {
boolean wasOdd = false;
for (Character c: str.toCharArray()) {
int counter = 0;
for (Character cc: str.toCharArray()) {
if (c == cc) {
counter++;
}
}
if (counter % 2 == 1) {
if (wasOdd) {
return false;
}
wasOdd = true;
}
}
return true;
}
public static void main(String args[]) throws Exception {
//Taking string input
//Scanner
Scanner s = new Scanner(System.in);
String str = s.nextLine();
if (Permutation.hasPalindrome(str)) {
System.out.println("YES"); // Writing output to STDOUT
} else {
System.out.println("NO"); // Writing output to STDOUT
}
}
}
Implementation from Checking if a String is a Permutation of a Palindrome
Time complexity is essentially O(n). This means that the function is linear in the length of the input string
public static boolean isPermutationOfPalindrome(String str) {
// Convert the input string to lower case and remove any non-letter characters
str = str.toLowerCase().replaceAll("[^a-z]", "");
// Create an array to count the frequency of each letter
int[] charCounts = new int[26];
for (int i = 0; i < str.length(); i++) {
charCounts[str.charAt(i) - 'a']++;
}
// Check if there is at most one character with an odd frequency
boolean foundOdd = false;
for (int count : charCounts) {
if (count % 2 == 1) {
if (foundOdd) {
return false;
}
foundOdd = true;
}
}
return true;
}

Resources